Skip to content

D3 — Licence posture for the serve plane

Status: PENDING HUMAN SIGN-OFF. Nothing below has been executed. The tree is Apache-2.0 (code) + CC-BY-4.0 (corpus) today and stays that way until somebody with standing signs this off; GOVERNANCE.md §6 records the question as open and points here. The contribution-rights half of the same question (D4) is decided and implemented — DCO, see §7 — because it is the reversible half.

The question. Keep Apache-2.0 across the whole tree and defend the commercial line with a trademark, or relicense the serve plane (tooling/openregs/serve/, the REST and MCP server) to AGPL-3.0 before the cloud product reaches GA.

Who is affected. Anyone embedding a client in an AI agent, any compliance team running openregs serve inside its own network, any packager reading the release manifest’s licenses: block, and every future contributor.


A hyperscaler takes openregs serve, points it at the public CC-BY-4.0 releases this project publishes, and sells “managed regulatory data” at a distribution advantage this project cannot match. Apache-2.0 permits that in full.

That is the Elastic/Mongo/Redis pattern and it is a real pattern. It is also, here, mostly a threat to the hosting line, and worth weighing against what the rehoster actually ends up holding:

  • They serve our releases, not their own. A release is a function of one commit and is signed. Producing a fresher one means running the ingestion pipeline against real regulator endpoints on a schedule, putting machine- proposed atoms in front of domain reviewers under per-regime governance, and signing the result. That is the company, not the server.
  • They cannot sign as us. openregs verify refuses a key that is not in config/trust.yaml, offline, in the consumer’s own process. A rehoster’s artifacts either verify against the public roots — in which case they are our bytes, unmodified, which decisions 5 and 6 deliberately allow — or they do not verify at all, and the thing a compliance team is buying is verification.
  • They cannot call it OpenRegs. That is CORE-4’s job and it is the control point the WordPress/Automattic history actually turns on.

And the decisive point about the remedy: AGPL does not stop this. AGPL §13 obliges an operator to offer the source of the version they run to users of the service. A rehoster running the serve plane unmodified discharges that by linking at this repository, in an afternoon. AGPL raises the cost of a differentiated proprietary fork of the server; it does almost nothing against a commodity rehost, which is the scenario named above. The historical responses to copyleft in this exact market were to fork the last permissive release, to reimplement the wire protocol, or simply to comply — never to stop.

So AGPL’s real value here is not defence. It is dual-licensing optionality: the ability to sell a proprietary exception to a customer who cannot take AGPL. That is a legitimate revenue model, and it is the only thing the relicense actually buys. §6 puts the question in those terms.

2. Adoption friction, for this consumer profile specifically

Section titled “2. Adoption friction, for this consumer profile specifically”

The friction is not generic. It lands hardest on exactly the three populations this project is being built for.

ConsumerWhat AGPL does to them
AI-agent builders embedding a clientThe clients are separate Apache-2.0 repos (openregs-js, openregs-go), so the licence does not reach them — but the header does. A reviewer who reads “OpenRegs is AGPL” stops there; licence posture is inherited by reputation long before it is inherited by law. And the #1 install reason the SDK phase names is pointing an agent at OpenRegs over MCP — the MCP server is the AGPL component, so any vendor who wants to bundle or redistribute a server hits it directly.
Enterprise compliance teams self-hosting openregs serveStated fairly: §13’s source offer runs to the users who interact with the service, so an internal-only deployment discharges it by offering source to the firm’s own employees, and nothing has to leave the building. That is the correct reading. It is not the reading that governs, because the team will modify — a bearer-token shim onto the corporate IdP, a reverse proxy, error rendering, something in config/serving.yaml that crosses from configuration into code — and somebody then has to certify, in writing, that the deployment never becomes externally reachable and that the internal offer is actually being made. Producing that certification is a legal engagement. Declining to deploy is free.
Anyone whose employer maintains an approved-licence listConcretely, what these lists block: AGPL is a flat denied entry in several widely copied corporate policies — Google’s third-party licence policy is the best-known and is imitated wholesale by companies that have never read it. Where it is not denied it is “escalate”: named legal review, an architecture note on how the code is deployed, and sign-off a level or two above the engineer who wanted to try it. In practice that converts a one-afternoon uv sync evaluation into a multi-week ticket, and most such tickets are abandoned rather than refused.

The asymmetry that matters: the people who would be stopped by AGPL are the compliance teams and agent builders this project needs as its first users. The party who would not be stopped is the hyperscaler, which has the legal capacity to comply or to route around it.

3. Coherence with decision 6 and with the CC-BY-4.0 half

Section titled “3. Coherence with decision 6 and with the CC-BY-4.0 half”

Decision 6 (“anything required to self-host stays OSS”) survives the letter of a relicense — AGPL is OSS — while losing its point. The rule exists so a firm can run the entire thing inside its own walls; an AGPL serve plane is precisely the component that firm’s legal review will refuse. Satisfying decision 6 by a definition that the population it protects cannot use is worse than not having made the promise.

The split artifact is the harder problem, because the split is not prose here — it is machine-readable in one place and rendered outward from it:

openregs.governance.licensing.RELEASE_LICENSES = {code: Apache-2.0, data: CC-BY-4.0}
→ release-meta.yaml `licenses:` (every built release, spec 1.2.0)
→ PyPI wheel `License:` and npm `package.json` `license`, as the SPDX
expression `Apache-2.0 AND CC-BY-4.0`
→ both packages' manifest.json, which keeps the mapping the expression cannot state

A serve-plane relicense makes licenses.code untrue as a single value. The release bundle contains generated code — constants-src/, which a customer compiles into proprietary systems — and that code must stay Apache-2.0 or the compiled constants inherit copyleft, which would defeat the entire codegen plane. So the manifest would have to carry either a third field or an expression like Apache-2.0 AND AGPL-3.0-only AND CC-BY-4.0. That expression is what every downstream SCA scanner reads, including for consumers who pull only the data package and never see a server. The cost of the relicense is therefore paid, in red findings in other people’s compliance tooling, by people who are not the threat.

4. The window, and what it costs to leave it open

Section titled “4. The window, and what it costs to leave it open”

History today: 148 commits, zero signed-off, no outside code contributions. Relicensing right now costs one commit and nobody’s permission. Every outside contributor after that is a copyright holder whose agreement is needed for a future change — unless they signed something that grants it in advance.

That is the D4 coupling, and it is strict: a DCO grants no relicensing right. The DCO certifies provenance — that the contributor may submit the patch under the project’s licence — and stops there. Keeping relicensing optionality open requires a CLA with an outbound-licence grant, and a CLA is a tax aimed at the same population AGPL is: the contributions this project most needs are atom reviews by domain experts inside regulated firms, and those are precisely the people who cannot sign a corporate CLA without a legal cycle. A CLA does not distinguish the CC-BY-4.0 data half from the Apache-2.0 code half, and neither will the reviewer reading it.

So the window is real, but holding it open is not free: it costs a CLA, from the first contribution onward, on every contributor.

Keep Apache-2.0 across the whole tree, keep CC-BY-4.0 for the corpus, and put the defensive weight on the trademark (CORE-4) and the signing identity and trust roots (ORG-5). Take the DCO for D4. The relicense does not stop the risk it is aimed at, and it stops the users the project is aimed at.

Consequences, stated plainly because they are the price:

  1. A hyperscaler may host our serve plane over our releases, and there is no licence remedy. Accepted deliberately: they cannot use the name, cannot sign as us, and cannot publish fresher law than the pipeline that produces it.
  2. The window closes. Once outside contributions land under DCO, relicensing requires their consent or a rewrite. Treat this as one-way. It can be reopened only by the trigger in §8, and reopening it then may simply not be available.
  3. The commercial line must be operations, and only operations — hosting, freshness SLA, private regimes, attestation. That is what §1 decision 5 already committed to; this recommendation refuses to hedge it with a licence.
  4. Dual-licensing revenue is given up. If selling a proprietary exception to the serve plane is ever wanted, it is not available after this.

Relicense tooling/openregs/serve/ to AGPL-3.0-only and adopt a CLA, taken now, before the first outside contribution.

Take this only if the answer to one question is yes: do you intend to sell proprietary exceptions to the serve plane? That is what it buys. If the answer is no, this path pays every cost in §2 and §3 for a defence §1 shows is not one.

Consequences:

  1. Adoption friction at the three populations in §2, worst at the self-hosting compliance team the product exists for.
  2. licenses: in every release manifest becomes a three-way statement, and every downstream SCA scan — including data-only consumers — reads copyleft.
  3. A CLA from day one, taxing domain-expert atom reviewers hardest.
  4. constants-src/ and the client SDKs must be explicitly carved out and kept Apache-2.0, in writing, or the codegen plane is unusable.
  5. In exchange: the option to sell an exception, and a real deterrent against a differentiated proprietary fork of the server — not against a plain rehost.

7. D4 — decided: DCO, and how it would be migrated

Section titled “7. D4 — decided: DCO, and how it would be migrated”

D4 is implemented as a DCO because it is the lean, it is cheap, and it is cheaply reversible. .github/workflows/dco.yml requires a Signed-off-by trailer naming the author on every commit a pull request adds; CONTRIBUTING.md states the rule and the reason.

If the human takes the §6 alternative, the DCO must be swapped for a CLA bot. The migration: stand up a CLA service (CLA Assistant or an equivalent that stores signatures in a repository, so the record is auditable rather than a vendor’s database), publish the agreement text under docs/ with an explicit outbound-licence grant covering both halves of the split, replace dco.yml with the bot’s check and swap the required context in .github/branch-protection.yaml so the two never overlap, and — the part that is not automatable — obtain a signature from every person who contributed under the DCO in the interval, since their sign-off granted nothing beyond the licence in force when they made it. That last step is why the interval matters: the migration is cheap at zero outside contributors and grows a person more expensive with each one.

Not a date. Revisit D3 when a named third party is operating a hosted OpenRegs at commercial scale, or when a customer asks in writing to buy a proprietary exception. Either is evidence; the absence of both is not a reason to pay §2’s costs in advance.


Every place the tree or a built artifact states a licence, read at the commit this document lands on. The Apache-2.0-code / CC-BY-4.0-data split is stated consistently everywhere; nothing contradicts anything.

WhereStatesConsistent
LICENSEApache-2.0, full textyes
regimes/LICENSE-DATASPDX-License-Identifier: CC-BY-4.0 + full text, and names /LICENSE as the code halfyes
NOTICEthe split table, the SPDX-header rule, the licenses: block, upstream publisher termsyes
README.md §Licensingthe same table, plus why CC BY 4.0 and not ODbLyes
pyproject.tomllicense = { text = "Apache-2.0" } — the wheel is code onlyyes
tooling/openregs/governance/licensing.pyCODE_LICENSE, DATA_LICENSE, RELEASE_LICENSES — the one place the choice is written downyes
tooling/openregs/release/build.pyemits licenses: into release-meta.yaml from RELEASE_LICENSESyes
tooling/openregs/release/packages.pyDEFAULT_LICENSES from the same constant; Apache-2.0 AND CC-BY-4.0 into the wheel and package.jsonyes
spec/schemas/release-meta.schema.jsonlicenses object, code + data required within it, optional overallyes
regimes/fixreg/releases/{2025.02,2025.04,2025.06}/release-meta.yaml{code: Apache-2.0, data: CC-BY-4.0} in all threeyes
fixtures/registry/… and fixtures/registry-tampered/… release-meta.yamlthe same blockyes
deploy/Dockerfileorg.opencontainers.image.licenses="Apache-2.0" — an image of the codeyes
docs/runbooks/release-build.md, docs/runbooks/release-publish.md, docs/schema-compatibility.mdthe same identifiers, sourced from RELEASE_LICENSESyes
MAINTAINERS.yaml/LICENSE and /regimes/LICENSE-DATA owned by governance — “relicensing is a governance act”yes
CONTRIBUTING.md house rulesmake check-licenses, the SPDX header gate, and that it never rewrites a differing identifieryes
.github/workflows/pr.yml lintruns openregs.governance.licensing --check on every pull requestyes

No dist/ exists in a clean checkout; built release metadata was read from the three committed releases and the two fixture registries instead, which is the same emission path.

Two observations, neither a defect:

  • pyproject.toml uses the older license = { text = … } table rather than a PEP 639 SPDX string with license-files. Both are valid; the wheel’s License: field is correct either way. Worth a look only when the packaging metadata is next touched.
  • The wheel carries no regimes/LICENSE-DATA, correctly — it contains no corpus. The data packages (openregs-data-<regime>) carry both identifiers through licenses_for, which is the artifact that needs the split.

None of these is owed while Apache-2.0 stands. Each becomes owed only if §6 is taken, and none may be started before sign-off:

  1. LICENSE — add the AGPL text as a second licence file and state the boundary (which directories each covers) at the top of both.
  2. NOTICE — extend the split table to three rows; it currently states the split as a two-row fact in prose that would become wrong.
  3. README.md §Licensing — same table, same problem.
  4. tooling/openregs/governance/licensing.pyRELEASE_LICENSES becomes more than two entries, and CODE_ROOT’s single-identifier header rule stops holding: check() would need a per-path expected identifier, and --fix’s refusal to rewrite a differing identifier becomes load-bearing rather than defensive.
  5. spec/schemas/release-meta.schema.jsonlicenses gains a field; that is a schema change with a compatibility entry owed in docs/schema-compatibility.md and a BUILDER_VERSION bump in tooling/openregs/release/build.py.
  6. The three standing releases and both fixture registries would be rebuilt and re-signed to carry the new block, per fixtures/registry/README.md.
  7. SPDX headers across tooling/openregs/serve/ rewritten, and the boundary between the serve plane and everything that imports it settled — cli/ invokes serve, and where the licence boundary falls across that call is the question the relicense actually has to answer.
  8. .github/workflows/dco.yml replaced per §7.

The size of that list is itself evidence for §5. The split is coherent in every place the table above names because all of them are generated or checked from one constant, and a partial relicense is precisely the change that constant cannot express.

Rendered from openregs/openregs@cbe9615:docs/decisions/d3-license-posture.md