Problem
RFC 0028 gave iohr extensions: separate programs, shipped as signed OCI artifacts,
verified before they run, pinned in a lock file and handed narrow, short-lived tokens. It
works for the agent (RFC 0029) and for the traffic capture companion (RFC 0061). It has
four limits that now matter:
- Only InOrbit publishes. A company that builds a check, a fault or a connector for its own systems has nowhere to put it, and nobody else can offer one.
- Nothing lists them. There are registry tags and no catalogue. Finding an extension means knowing its name.
- Nothing says what an account may install. Plans grant units and nothing else
(RFC 0015). RFC 0061 adds the entitlements API, with an
extensionsfield reserved and empty. - Nothing runs inside the console. The console has a fixed navigation, no content security policy and no frame isolation. A script on its origin would act with the person's full session, so third-party interface code cannot run there at all.
The owner wants a marketplace: InOrbit's own extensions, a company's private ones, free ones from other publishers and paid ones sold through us. A marketplace is also where a platform built on "AI engineering that has to prove its work" (RFC 0045) can lose the thesis fastest. A catalogue of claims a publisher makes about itself is the opposite of evidence.
Proposal
Why, in the terms of the loop
Extensions are workloads and primitives of the engineering loop, not a product of their own:
- checks, faults and discovery the agent runs (observe, experiment);
- connectors, so the platform can act on another system (change);
- console panels that show a measurement or a verdict (verify, evidence);
- assistant plugins, so an assistant can reach the bench (RFC 0040.14).
Every listing shows its evidence. Each version carries the records of its own verification runs (RFC 0046): the publisher's build provenance, our automatic checks, a recorded run on a clean machine that installs it, runs its declared self-test and shows which scopes it actually asked for, and, for checks and faults, a graded run against a known injected fault. Dimensions are shown separately, never as one score. A version with no evidence says "no evidence yet" and is not hidden or dressed up. A publisher's own description is shown as the publisher's words.
What an extension is
One manifest, the RFC 0028 config, gains a kind. Absent means program, so every
existing artifact stays valid.
| Kind | What it is | Where it runs | Granted by default |
|---|---|---|---|
program |
the RFC 0028 kind, a separate program iohr runs |
the person's machine or a pipeline | the declared scopes over the token channel; privileges shown and confirmed (below) |
agent-plugin |
a WebAssembly component (WASI 0.2) | inside the agent (RFC 0029) | nothing; capabilities for checks, faults or discovery, within the hosts and scopes the agent's policy allows |
web |
a console panel or widget | a sandboxed frame on a separate user-content domain | nothing; calls go through a bridge with a per-install token |
connector |
connector definitions as data, the RFC 0044 schema | the connections service | what the person grants when connecting, as for built-in connectors |
assistant-plugin |
a thin MCP plugin (RFC 0040.14) | the person's assistant | the person's own token and its scopes |
Programs keep RFC 0028's rules unchanged. The privileges field (added with RFC 0061)
is how a listing declares the Linux capabilities its system service needs: iohr grants
none of them, shows them in plain words at install, asks for a typed confirmation, asks
again when an upgrade adds one, records them in the lock file and refuses to sync an
artifact that declares more than its lock entry. The catalogue shows the same list on the
listing, so the decision can be made before anything is downloaded.
Agent plugins are the shape RFC 0028 set aside for small extensions written by others. A component gets no file system, no network and no clock beyond what the host hands it. The agent grants interfaces per capability (an HTTP check against a host the policy allows, a fault through the agent's proxy, a discovery read) with memory and time budgets, and the plugin's declared capabilities are checked against the policy before it loads.
Web extensions never run in the console's origin:
- Each one is served from a separate registrable user-content domain, one subdomain per extension, never a subdomain of the console's or the site's domain. The domain goes on the Public Suffix List so no two extensions share cookies or storage.
- The console embeds it in a frame with
sandbox="allow-scripts"and neverallow-same-origin, so the frame has an opaque origin even on its own domain. - It talks to the console only through a message bridge, a small package
(
@inorbithr/ext-web). The console checks each call against the install's manifest and relays it to the API with a short-lived token for that install: its own audience, only the manifest's scopes, never the person's session. - The console gains a content security policy whose
frame-srcnames the user-content domain only. The agent's local admin page takes the same model if it ever hosts panels.
A diagram is drawn here in the RFCs product; this page does not show diagrams yet.
Connectors are the lowest-risk kind: data in the schema RFC 0044 already compiles in, run by the connections service's own executors. Publishing them as data instead of in the binary is what makes them versioned and installable per account.
Publishers and namespaces
A publisher is an account, a person's or a team's, with a namespace: inorbit/agent,
acme/billing-checks. A bare name keeps working as an alias for InOrbit's namespace, so
iohr ext install agent means inorbit/agent. A publisher has:
- a proved domain (RFC 0030), shown on every listing;
- a signing identity: a Sigstore OIDC identity, a repository and a release workflow,
registered per listing.
iohraccepts a version only when its signature and its provenance come from that identity; - for paid listings, a Stripe Connect account (below);
- trader details for consumers in the EU (below).
The catalogue and who sees what
A new extensions service, scaffolded with tbd new service extensions, holds
publishers, listings, versions, kinds, scopes, privileges and capabilities, evidence,
prices and licences. A listing is one of:
- public: anyone signed in sees it;
- private: the publishing account and the accounts it names. Everyone else gets NOT_FOUND, never a listing that exists and is refused, the same rule internal labs follow;
- included: InOrbit's own, granted by a feature of a plan in the entitlements data;
- paid: a price, and a licence per account once bought.
What an account may install is one answer, given in one place: the extensions field of
GET /v1/accounts/orgs/{org}/entitlements (RFC 0061). The accounts service fills it by
asking the catalogue, which answers from the account's features (included), its private
listings and its licences. The catalogue never calls back into accounts for that answer,
so the two services do not depend on each other in a loop. iohr ext install reads the
same field, and the catalogue checks it again before it hands out anything that lets an
artifact be pulled.
Search and reading come through iohr ext search|show, the console, /v1/extensions and
MCP read tools. Every list is paged (RFC 0033).
Install counts come only from the catalogue's own records (licences and pull tokens). The command line still sends no telemetry, and a public artifact pulled from a company's mirror is never counted.
Artifacts, trust and revocation
- Where artifacts live. InOrbit's stay where RFC 0028 put them. Third-party artifacts
are pushed to our registry under
iohr-ext/<publisher>/<name>. Private and paid ones need a registry we control, whose token service asks the catalogue: a short-lived pull token is minted only after the entitlement check, as the OCI distribution protocol's bearer token flow allows. - What
iohrchecks before anything runs:- the digest and size of every manifest and blob, as today;
- the publisher's signature and provenance, against the identity registered for the listing (for InOrbit, our release workflow, as today);
- for a public third-party listing, our review attestation as well, a signed statement naming the artifact's digest, from our review workflow's identity;
- a signed revocation list from the catalogue, fetched at
install,upgrade,syncandverifyand never otherwise. A revoked digest is refused, andiohr <name>refuses to start one the last fetched list names.
- Private enterprise extensions need only the enterprise's own identity or keys
(
ext.trusted_keys), no review by us. - Company mirrors keep working. The registry and the catalogue on the API host stay the
only hosts
iohrcontacts for extensions, and only inextcommands.
A diagram is drawn here in the RFCs product; this page does not show diagrams yet.
Review and takedown
- Automatic checks on every version: a manifest lint; a diff of scopes, privileges and capabilities against the previous version; an SBOM and a vulnerability statement present (CycloneDX, OpenVEX); a scan for known vulnerabilities; size limits; for web extensions a check of the bundle against the frame's rules (no remote script, no attempt to reach outside the bridge).
- A person reviews the first public version of a listing, and every version that widens its scopes, privileges or capabilities. The review attestation is signed only after that.
- Takedown. Anyone can report a listing (the notice-and-action duty of the Digital Services Act, Article 16). A report gets an acknowledgement, a decision with its reasons for both sides, and a way to contest it. Takedown removes the listing, adds the digests to the revocation list, and for web extensions switches them off on the server at once, since a frame loads from our domain on every view.
- Every action is audited: who, what, outcome, never the content of a report beyond its category.
Merchant mode
A person or a team switches the console into merchant mode, the way they switch teams. It is the publisher's side of the catalogue, one place for everything a publisher does:
| Part | What it shows and does | Lands in phase |
|---|---|---|
| Publisher profile | namespace, proved domain, signing identities | 1 (for private listings), 3 (identities for public ones) |
| Listings and versions | create a listing, its visibility, each version with its checks and evidence | 1 |
| Previews | a web extension rendered in its frame against test data | 2 |
| Review status | each version's automatic checks, the human review, what to fix | 3 |
| Notices | reports and takedown decisions, with the contest route | 3 |
| Trader details | what EU consumers are shown | 3 |
| Prices | per listing: one-off or subscription | 4 |
| Sales and licences | who holds a licence (an account, never a person's details beyond what the publisher must have), refunds, disputes | 4 |
| Payouts | balance and payouts, through Stripe's Express dashboard | 4 |
Merchant mode follows the same visibility rule as the rest of the product while it is built: it works for every account it applies to, and is shown only to admins and partners (RFC 0057) until the owner opens it.
Paid listings
The owner decided on 2026-10-05: the first release opens everything, third-party paid listings included, and money flows through Stripe Connect with a revenue share.
- Accounts. Each paid publisher onboards to a Stripe Express connected account. Stripe collects and verifies the publisher's identity and bank details, which also covers most of the trader details.
- Charges. A destination charge on our platform account per sale, with our share as the application fee and the rest transferred to the publisher (Stripe, destination charges). Prices are one-off or subscriptions per listing.
- Licences are entitlements in the
extensionsservice, granted only on Stripe's signed event (as plans are in RFC 0052, never on a return page), checked at install and before every pull token. - Refunds and disputes follow the publisher terms. A refund or a lost dispute ends the licence.
How the money and the licence move in test mode (phase 4 as built): the buyer pays the platform, the platform keeps its share and the rest goes to the publisher's payout account, and only the payment provider's signed events make billing grant or end the licence in the catalogue.
A diagram is drawn here in the RFCs product; this page does not show diagrams yet.
An unresolved question blocks real money, not the build. It is the owner's and the accountant's to answer, and this RFC does not answer it. What is known:
- Our plans are sold through Stripe Managed Payments, Stripe as the merchant of record (RFC 0052). That was chosen on 2026-09-29 because, under Croatia's Fiskalizacija 2.0 (Narodne novine 89/2025, from 2026-01-01), every sale to a Croatian consumer must be fiscalised whatever the payment method, EU consumers need the OSS scheme, and each payment would want an invoice from us. With a merchant of record, the company makes one supply to Stripe per payout instead.
- Stripe's own documentation lists Connect, "platform or marketplace integrations", as unsupported by Managed Payments (Stripe, Managed Payments). Paid extensions cannot ride on the arrangement our plans use.
- EU VAT presumes that a platform taking part in a supply of electronically supplied services acts in its own name, and a platform that authorises the charge, the delivery or sets the general terms cannot point to the publisher as the supplier (Implementing Regulation (EU) No 282/2011, Article 9a). A checkout we run probably does at least one of those.
The options, without a preference:
- Connect on our own Stripe account, InOrbit the seller of every paid extension. Plans stay on Managed Payments. Paid extensions carry VAT we charge (Stripe Tax can compute it), OSS returns, reverse charge for business buyers, fiscalised receipts for Croatian consumers and invoices from us; publishers invoice us for their share, or we self-bill. Two tax regimes side by side.
- Connect with the publisher as the merchant on each charge. The publisher's name is on the receipt. Under Article 9a we may still be the deemed supplier for VAT, so this may change the paperwork and not the duty. Only the accountant can say.
- Everything off Managed Payments: plans and extensions both on Stripe direct with Stripe Tax. One regime, and it brings back the OSS and fiscalisation work the 2026-09-29 decision avoided, for our plans too.
- No money through us. Publishers sell licences through their own merchant of record, and the catalogue checks a licence the publisher's system issues. No Connect and no revenue share, which reverses the owner's decision of 2026-10-05.
- A merchant of record that pays out to sellers. Not researched yet; listed so the accountant can ask whether one fits.
The owner's choice, 2026-10-06, pending the accountant: option 1. InOrbit is the seller of every paid extension; publishers are paid through Stripe Connect destination charges with our share as the application fee. The first release sells third-party paid listings only to business buyers with a VAT ID (reverse charge within the EU; an eRačun for a Croatian business, which the finance service already sends). Publishers' shares are self-billed if the accountant agrees. Plans stay on Managed Payments. Connect was checked working in the Stripe test account. Live money still waits on the accountant's answers.
Until there is an answer, paid listings run in Stripe test mode and refuse a live key, as billing did. The phase 4 build is the same in test mode for options 1 and 2; options 3 and 4 change it. Three more things wait with the answer: the publisher terms, the refund and dispute policy, and the revenue share percentage.
Compliance and risk
This states how the design lines up with the obligations we know of. It is not a claim of compliance with anything.
- Third-party code is a supply-chain risk. The controls are the ones above: publisher signatures checked against a registered identity, our review attestation, scopes and privileges declared and shown, sandboxes with nothing granted by default, and revocation.
- Digital Services Act (Regulation (EU) 2022/2065). Notice and action (Article 16) applies to us as a host. Traceability of traders (Article 30) applies to platforms where consumers buy from traders; Article 29 exempts micro and small enterprises, which InOrbit is today. We collect the trader details anyway, from the first paid listing, because Connect onboarding gathers most of them and the exemption ends as the company grows.
- Cyber Resilience Act (Regulation (EU) 2024/2847). For a third-party extension we offer, our role is closest to a distributor's (Article 20): we check that the publisher's product carries what the Act requires before we list it, and we act on a vulnerability we learn of. A publisher's own obligations stay the publisher's. Our own extensions remain products we make, as RFCs 0029 and 0061 say.
- Personal data. Customer data reaches a publisher only through scopes an install grants, and the consent screen says so in plain words. A publisher sees a licence holder as an account; anything more needs the buyer's choice. Paid listings make Stripe Connect a new use of an existing vendor.
- The compliance registry (
inorbithr/compliance) needs entries before the first third party publishes: access control for publishers and merchant mode, supply chain for third-party artifacts and review, the Stripe Connect use in the vendor register, and the marketplace obligations (notice and action, trader details, distributor duties). - Visibility. Every console part ships working for every account it applies to and shown only to admins and partners until the owner opens it.
Plan
The phases are the order of building within the first release. Nothing becomes visible to
everyone until the owner opens it, and no real money moves until the question above is
answered. Each phase is a pull request (or a few) with its checks; migrations are made with
mise run db:new; integration tests boot real servers on a free port, with no mocks of our own
services.
| Phase | Where | What |
|---|---|---|
| 1. The catalogue | core, sdk | the extensions service; InOrbit listings; private listings; the entitlements extensions field filled; console "Extensions"; merchant mode's profile, listings and versions; iohr ext search and iohr ext show |
| 2. Web extensions | core, sdk | the user-content domain, the frame host, the bridge package, the console's content security policy, per-install tokens; merchant mode previews |
| 3. Public third-party publishing | core, sdk | publisher signing identities; the review pipeline and attestations; the revocation list; the connector kind; reports and takedown; trader details; iohr ext publish and iohr ext init |
| 4. Paid listings | core | Connect onboarding, prices, checkout, licences, pull tokens, payouts, refunds; test mode only until the money question is answered |
| 5. Agent plugins and remote tools | core, dataplane | WebAssembly components in the agent; MCP tools contributed by extensions |
Phase 1: the catalogue
- Service.
mise run tbd -- new service extensions(crate, proto, configs, deployment, chaos adapter, every shared registration), thentbd service check extensions. - Proto.
proto/iohr/extensions/v1/extensions.proto:ListExtensions(paged, a query, filters by kind and visibility),GetExtensionandListVersionsbypublisher/name,CreateListing,UpdateListing,AddVersion(a digest, the manifest read from the artifact, the signer),GetPublisherandUpsertPublisher, and the internalListEntitledthe accounts service calls. Each read withgoogle.api.httpunder/v1/extensions. - Migration. One,
mise run db:new extensions_catalogue: publishers (account, namespace, domain reference), listings (visibility, kind, the accounts a private listing names), versions (digest, manifest, signer, scopes, privileges, capabilities), evidence references (record ids from RFC 0046, never content), and an audit trail. - InOrbit listings (the agent, capture, console) seeded from the release metadata of their signed artifacts, not typed by hand.
- Entitlements. The accounts service fills
extensionsfromListEntitled, with the account's features passed in. - Gate. Every route names a token requirement at the edge; reads need the new
extensions:readscope or a signed-in person; writes are a person's, for their own account. Default deny. - Console.
ui/console/src/app/extensions/: browse, a listing page with its kind, publisher, scopes, privileges, evidence per version, and how to install it (iohr ext install <publisher>/<name>, copyable); merchant mode's profile, listings and versions. Shown to admins and partners innav.tsand the account menu, working for every role it applies to. - Command line (
inorbithr/sdk):iohr ext search <query>andiohr ext show <publisher>/<name>over the API host (no new host, so its network rules do not change),--jsonon both, and thepublisher/nameform ininstall. Private listings install from the enterprise's own registry, verified with its own keys. - MCP. Read tools for search and show, behind
extensions:read. - Tests. A private listing is NOT_FOUND for every other account, including through
search; entitlements list exactly the included, private and licensed extensions; a
version whose signer differs from the listing's identity is refused;
buf lint; the console page for a personal account, a team owner and a team member. - Docs.
docs/extensions/README.md, the API reference, the command line's reference.
Phase 2: web extensions
- The user-content domain (an open question below), its edge route serving extension bundles only, the Public Suffix List entry.
- The frame host in the console and
@inorbithr/ext-web(bridge, types, a template). - The console's content security policy,
frame-srclimited to the user-content domain. - Per-install tokens. This depends on the sign-in service narrowing a token (token exchange, RFC 8693), which the command line's channel waits on too; until then web extensions stay admin-only.
- The server-side switch that stops a web extension loading.
- Tests: a frame cannot read the console's cookies or storage; a call outside the manifest's scopes is refused at the bridge and at the API; a switched-off extension stops loading on the next view.
Phase 3: public third-party publishing
- Publisher signing identities per listing, checked by
iohr(inorbithr/sdk: a trust policy per listing instead of one workflow identity). - The review pipeline: the automatic checks, the queue for a person, the review attestation signed by our review workflow.
- The revocation list, signed, served by the catalogue, fetched by the four
extcommands. - The
connectorkind in the connections service. - Reports, decisions, contest, takedown; trader details.
iohr ext init(a template per kind) andiohr ext publish(pushes to our registry, opens the version).- Tests: an artifact signed by a different identity is refused; a public third-party version without a review attestation is refused; a revoked digest is refused at install and at start.
Phase 4: paid listings
- Connect onboarding (Express) from merchant mode; prices; Checkout for a listing; destination charges with the application fee; the webhook events that grant and end licences; pull tokens from the private registry's token service; payouts; refunds.
- A migration for prices, licences and Connect account ids (no card, no bank details, no amounts beyond what a licence needs).
- Test mode only; a live key is refused until the money question is answered.
- Tests against a recorded Stripe API: a licence only on the signed event; a refund ends it; a pull token is refused without a licence.
Phase 5: agent plugins and remote tools
- The agent hosts WebAssembly components with interfaces per capability, budgets and the
policy check (
inorbithr/dataplane). - Extensions that contribute MCP tools to the platform's server, each tool behind its install's scopes.
- Tests: a plugin with no granted capability cannot reach the network or the file system; a plugin over its budget is stopped and the run recorded as failed.
Later, not in this RFC
Other channels, such as a cloud provider's marketplace, are possible once the catalogue exists. None is planned.
Alternatives considered
Install from any repository, as gh extension install does. No catalogue to run, and
the trust decision is the person's alone with no record a security team can review. RFC
0028 refused it for the same reason.
Third-party interface code in the console's own origin. Simplest to build, and any extension would hold the person's whole session. Refused; that is why web extensions get a separate domain.
Web extensions on inorbit.page. We own it already. It hosts published labs
(RFC 0039), and an extension sharing a registrable domain with customer sites mixes two
kinds of untrusted content. A dedicated domain is cleaner.
Only InOrbit publishes, indefinitely. The safest catalogue and a small one. It leaves a company's own checks and connectors without a home, and the owner decided to open it.
A separate marketplace product with its own accounts. Publishers are accounts already, with proved domains, roles and audit. A second identity system would duplicate them.
Decision
Open. Decided by the owner: a marketplace with InOrbit's, private, free and paid listings, all in the first release (2026-10-05); Stripe Connect with a revenue share (2026-10-05); phase 1 as above, started now (2026-10-06). Open:
- The revenue share percentage.
- How the money and the VAT work (the five options under Paid listings). The owner chose option 1 on 2026-10-06 (InOrbit the seller, Connect destination charges, business buyers with a VAT ID only at first, plans staying on Managed Payments), pending the accountant's answers. Real money waits on them.
- The user-content domain to buy for web extensions (recommended: a new one, not
inorbit.page). - Whether third parties may publish the
programkind in phase 3, or only the sandboxed kinds (agent-plugin,web,connector) at first.
Publication
The console gains "Extensions" and merchant mode, shown to admins and partners first. The
command line's reference gains iohr ext search and iohr ext show, the developer docs a
page on the catalogue. RFC 0028's status log points here. Nothing on the site describes a
kind, a third-party listing or a paid extension as available before it is.
Status log
2026-10-06: opened, with the owner's decisions of 2026-10-05 and 2026-10-06. Builds on RFC 0028 and RFC 0061's entitlements API, which is being built. Nothing of this RFC is built yet.
2026-10-06: phase 1 design, written before it is built. The
extensionsservice (tbd new service extensions, schemaextensions) holds publishers (a namespace per account;inorbitis InOrbit's own account), listings (publisher/name, kind, the publisher's description shown as the publisher's words, visibilitypublicorprivate, the accounts a private listing names, a feature that includes it,comingwhile nothing is released), versions (the OCI index digest, the manifest's scopes, privileges and entrypoint, the signer identity, the platforms) and evidence references (empty in phase 1: every version says "no evidence yet"). A private listing is visible to its publisher's account and the accounts it names; to anyone else it does not exist (NOT_FOUND, and never in a search). Reads are/v1/extensions(search, paged),/v1/extensions/{publisher}(a publisher),/v1/extensions/{publisher}/{name}and.../versions, for a signed-in person or a key holding the newextensions:read, acting for their own account or a team they belong to. Writes (a publisher, a listing, a version) are a person's, for their own account, and need the platform's admin role until third parties publish (phase 3). InOrbit's listings are seeded from data generated from the registry (mise run extensions:seed: each release's index digest, the manifest's config and the signer read from its Sigstore bundle), never typed by hand: the agent with its released versions, and capture marked "coming" until its first signed release. Internal RPCs, never over HTTP:ListEntitledfor the accounts service (included by a feature, private, licensed), and licences for the billing service (GrantLicencean upsert bysource,EndLicenceidempotent,HasLicence,GetListingSeller). A licence is never deleted, only ended, and holds no amount, card or tax id. Every call is audited (who, what, outcome, never a description or a query). Erasure removes a person's account's listings and publisher and detaches a person from what they made; licences stay with the account that holds them. The console's Extensions page (browse, search, a listing with versions, scopes, privileges and the install command) is shown in the sidebar to admins and partners and works for every role. MCP read toolsextensions_*needmcp:readandextensions:read. The accounts service's call toListEntitledlands after the entitlements API (#422) merges;iohr ext search|showfollow in the sdk once this API is merged.2026-10-06: phase 4, the money side, built in billing in Stripe test mode (option 1 as the owner chose it pending the accountant: InOrbit the seller, business buyers only for third-party listings). Publishers onboard to Connect Express from billing, which keeps only the account id and Stripe's flags. A publisher sets one price per listing, one-off or a subscription per seat. Checkout is a destination charge with the application fee; the share is 20 % with the rest to the publisher's verified Connect account (owner, 2026-10-06); InOrbit d.o.o. sells its own listings. Every paid listing needs the buyer's VAT ID verified by Stripe until the accountant answers (
vat_id_required = "all"), and a publisher who can receive transfers. Licences are granted and ended only on Stripe's signed events: paid, each paid invoice, a full refund, a lost dispute, a cancelled or lapsed subscription. A test-mode sale grants only to the named test accounts. The calls to the extensions service sit behind a trait until its client is wired, so nothing is on sale in a deployment yet. Not built: pull tokens, the merchant mode pages, Stripe Tax.2026-10-07: phase 1 in review (#492): the
extensionscatalogue service, the console's Extensions page, theextensions:readscope with four read-only MCP tools, and the licence calls billing makes. It is not merged or rolled. Phase 4's billing side (#441) is merged and stays off in every deployment until billing's client for the catalogue is wired. The review of #492 left six follow-ups that must land before billing grants a licence: a refunded or disputed sale is never reinstated by a later event; two first grants for the same sale at once; retired namespaces; pinning the signer of InOrbit's seeded listings and verifying it; query strings kept out of the edge's access logs; and licences in an account's export. Next after the merge:iohr ext searchandiohr ext show.2026-10-07: Checked: #441 is live; #492 is merged, not deployed; #482 is merged, not rolled. Open.
2026-10-07: billing calls the catalogue for real: who sells a listing, and the licence granted or ended on each signed payment event, tested end to end against the catalogue service. Still off in every deployment until the catalogue's review follow-ups land (no reinstating refunded, disputed or one-off licences, an end-before-grant tombstone, concurrent first grants, retired namespaces, signer pinning, licences in export). The money flow is drawn above.
2026-10-08: Part RFC 0073.1 written: agent extensions as the unit of functionality and of entitlement, with a
builtindelivery for InOrbit's own areas (ADR 0060); bundles by file for air-gapped sites in RFC 0092.1. Marked for the owner's decision (RFC 0100, D4).