@ours.network/notifications 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +98 -0
- package/README.md +231 -0
- package/dist/cli.js +446 -0
- package/dist/config.js +104 -0
- package/dist/daemon.js +353 -0
- package/dist/http.js +31 -0
- package/dist/log-store.js +48 -0
- package/dist/presence.js +157 -0
- package/dist/provision.js +29 -0
- package/dist/push.js +6 -0
- package/dist/web-push-sender.js +41 -0
- package/mufl_code/20E39399689579D5AFA5132C59DEDDD328C3BCA1A74D546F2193B36585DDD283.muflo +0 -0
- package/mufl_code/config.mufl +21 -0
- package/mufl_code/core/.github/FUNDING.yml +3 -0
- package/mufl_code/core/.github/workflows/docs.yml +39 -0
- package/mufl_code/core/.github/workflows/tests.yml +66 -0
- package/mufl_code/core/COMMERCIAL-LICENCE.md +25 -0
- package/mufl_code/core/COMPATIBILITY.md +221 -0
- package/mufl_code/core/CONTRIBUTING.md +37 -0
- package/mufl_code/core/LICENSE +98 -0
- package/mufl_code/core/NOTIFICATIONS_CONTRACT.md +290 -0
- package/mufl_code/core/README.md +91 -0
- package/mufl_code/core/SECURITY.md +40 -0
- package/mufl_code/core/TRADEMARKS.md +24 -0
- package/mufl_code/core/a2a_capabilities.mm +449 -0
- package/mufl_code/core/a2a_cluster.mm +601 -0
- package/mufl_code/core/a2a_control.mm +90 -0
- package/mufl_code/core/a2a_messaging.mm +4817 -0
- package/mufl_code/core/a2a_monitoring.mm +94 -0
- package/mufl_code/core/a2a_notification_integration.mm +144 -0
- package/mufl_code/core/a2a_notifications.mm +1127 -0
- package/mufl_code/core/a2a_protocol.mm +246 -0
- package/mufl_code/core/a2a_versions.mm +801 -0
- package/mufl_code/core/config.mufl +29 -0
- package/mufl_code/core/docs/.vitepress/config.mts +58 -0
- package/mufl_code/core/docs/citations.json +688 -0
- package/mufl_code/core/docs/guide/01-vendor-the-core.md +50 -0
- package/mufl_code/core/docs/guide/02-configure-and-compile.md +100 -0
- package/mufl_code/core/docs/guide/03-wire-the-host.md +154 -0
- package/mufl_code/core/docs/guide/04-connect-and-message.md +156 -0
- package/mufl_code/core/docs/guide/05-test-your-app.md +75 -0
- package/mufl_code/core/docs/guide/index.md +63 -0
- package/mufl_code/core/docs/how-it-works/capabilities-and-control.md +77 -0
- package/mufl_code/core/docs/how-it-works/cluster.md +65 -0
- package/mufl_code/core/docs/how-it-works/identity.md +56 -0
- package/mufl_code/core/docs/how-it-works/invites-and-contacts.md +76 -0
- package/mufl_code/core/docs/how-it-works/messaging.md +55 -0
- package/mufl_code/core/docs/how-it-works/monitoring-and-config.md +72 -0
- package/mufl_code/core/docs/how-it-works/overview.md +45 -0
- package/mufl_code/core/docs/how-it-works/versioning.md +116 -0
- package/mufl_code/core/docs/index.md +27 -0
- package/mufl_code/core/docs/package-lock.json +3467 -0
- package/mufl_code/core/docs/package.json +15 -0
- package/mufl_code/core/docs/reference/contributing.md +26 -0
- package/mufl_code/core/docs/reference/glossary.md +108 -0
- package/mufl_code/core/docs/reference/implementations.md +23 -0
- package/mufl_code/core/docs/reference/modules.md +19 -0
- package/mufl_code/core/docs/scripts/check-citations.mjs +36 -0
- package/mufl_code/core/docs/scripts/check-denylist.mjs +30 -0
- package/mufl_code/core/docs/scripts/gen-llms.mjs +32 -0
- package/mufl_code/core/docs/workflows/cluster.md +89 -0
- package/mufl_code/core/docs/workflows/contact-exchange.md +60 -0
- package/mufl_code/core/docs/workflows/contact-restore.md +60 -0
- package/mufl_code/core/docs/workflows/control-verbs.md +70 -0
- package/mufl_code/core/docs/workflows/index.md +57 -0
- package/mufl_code/core/docs/workflows/introductions.md +60 -0
- package/mufl_code/core/docs/workflows/messaging.md +75 -0
- package/mufl_code/core/docs/workflows/monitoring.md +84 -0
- package/mufl_code/core/docs/workflows/notifications.md +109 -0
- package/mufl_code/core/release-notes/0.1.md +60 -0
- package/mufl_code/core/release-notes/0.3.md +22 -0
- package/mufl_code/core/release-notes/0.4.md +97 -0
- package/mufl_code/core/tests/README.md +83 -0
- package/mufl_code/core/tests/compat/README.md +82 -0
- package/mufl_code/core/tests/compat/compat.mjs +245 -0
- package/mufl_code/core/tests/compat/compat_peer.mjs +146 -0
- package/mufl_code/core/tests/compat/run_compat.sh +96 -0
- package/mufl_code/core/tests/corpus.mjs +139 -0
- package/mufl_code/core/tests/corpus_actor.mu +242 -0
- package/mufl_code/core/tests/fatcompile_actor.mu +52 -0
- package/mufl_code/core/tests/mig.mjs +805 -0
- package/mufl_code/core/tests/mig_actor.mu +518 -0
- package/mufl_code/core/tests/migapp.mjs +431 -0
- package/mufl_code/core/tests/migapp_actor.mu +294 -0
- package/mufl_code/core/tests/mufl_semantics/run.sh +69 -0
- package/mufl_code/core/tests/mufl_semantics/t11_three_version.mufl +47 -0
- package/mufl_code/core/tests/mufl_semantics/t2_extra_fields.mufl +11 -0
- package/mufl_code/core/tests/mufl_semantics/t7_runtime.mufl +30 -0
- package/mufl_code/core/tests/mufl_semantics/t9_passthrough.mufl +19 -0
- package/mufl_code/core/tests/mufl_semantics/t_str_order.mufl +19 -0
- package/mufl_code/core/tests/notif.mjs +755 -0
- package/mufl_code/core/tests/notif_actor.mu +450 -0
- package/mufl_code/core/tests/protocol_container.mm +18 -0
- package/mufl_code/core/tests/run.sh +65 -0
- package/mufl_code/core/tests/run_corpus.sh +51 -0
- package/mufl_code/core/tests/run_fatcompile.sh +40 -0
- package/mufl_code/core/tests/run_mig.sh +51 -0
- package/mufl_code/core/tests/run_migapp.sh +51 -0
- package/mufl_code/core/tests/run_notif.sh +57 -0
- package/mufl_code/core/tests/test.mjs +750 -0
- package/mufl_code/core/tests/test_actor.mu +564 -0
- package/mufl_code/core/tests/test_common.mjs +93 -0
- package/mufl_code/core/version.mm +24 -0
- package/mufl_code/packet.mu +170 -0
- package/mufl_code/protocol_container.mm +18 -0
- package/package.json +43 -0
- package/scripts/gen-vapid.mjs +16 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// ours-notifications service packet — compile configuration.
|
|
2
|
+
// Full ADAPT stdlib + the shared ours mufl core (mufl_code/core/ submodule)
|
|
3
|
+
// + the protocol_container boot stub the SDK wrapper executes at packet
|
|
4
|
+
// registration.
|
|
5
|
+
config script
|
|
6
|
+
{
|
|
7
|
+
stdlib_config = (config_load #$MUFL_STDLIB_PATH).
|
|
8
|
+
core_config = (config_load #"core").
|
|
9
|
+
|
|
10
|
+
(
|
|
11
|
+
$imports ->
|
|
12
|
+
(
|
|
13
|
+
$libraries -> (stdlib_config $exports $libraries)'(core_config $exports $libraries)'($protocol_container -> #"protocol_container.mm"),
|
|
14
|
+
),
|
|
15
|
+
$exports ->
|
|
16
|
+
(
|
|
17
|
+
$libraries -> (,),
|
|
18
|
+
$applications -> (,)
|
|
19
|
+
)
|
|
20
|
+
).
|
|
21
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
name: docs
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches: [main]
|
|
5
|
+
paths: ['docs/**', '.github/workflows/docs.yml']
|
|
6
|
+
pull_request:
|
|
7
|
+
paths: ['docs/**', '.github/workflows/docs.yml']
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
build:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
defaults: { run: { working-directory: docs } }
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
- uses: actions/setup-node@v4
|
|
19
|
+
with: { node-version: 20, cache: npm, cache-dependency-path: docs/package-lock.json }
|
|
20
|
+
- run: npm ci
|
|
21
|
+
- run: npm run docs:check
|
|
22
|
+
- run: npm run docs:build
|
|
23
|
+
- run: node scripts/gen-llms.mjs
|
|
24
|
+
- uses: actions/upload-pages-artifact@v3
|
|
25
|
+
with: { path: docs/.vitepress/dist }
|
|
26
|
+
|
|
27
|
+
deploy:
|
|
28
|
+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
29
|
+
needs: build
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
permissions:
|
|
32
|
+
pages: write
|
|
33
|
+
id-token: write
|
|
34
|
+
environment:
|
|
35
|
+
name: github-pages
|
|
36
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
37
|
+
steps:
|
|
38
|
+
- id: deployment
|
|
39
|
+
uses: actions/deploy-pages@v4
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Core test suite — fully self-contained (house rule: in-repo orchestration, no
|
|
2
|
+
# committed binaries, no self-hosted runner). The toolchain and runtime come from
|
|
3
|
+
# the PUBLISHED @adapt-toolkit packages; the broker is the standalone
|
|
4
|
+
# @adapt-toolkit/broker bin (the sdk's embedded dev broker was removed in the
|
|
5
|
+
# #137 line). The runner scripts expect an adapt-checkout layout, so a 4-symlink
|
|
6
|
+
# shim over the npm mufl package provides it.
|
|
7
|
+
#
|
|
8
|
+
# TOOLCHAIN_VERSION pins the exact published tuple the suite runs under — bump
|
|
9
|
+
# it deliberately alongside consumer pins (see the ours ecosystem VERSIONS.md
|
|
10
|
+
# discipline), never with a range.
|
|
11
|
+
name: tests
|
|
12
|
+
|
|
13
|
+
on:
|
|
14
|
+
push:
|
|
15
|
+
branches: [main, 'fable/**', 'feat/**', 'fix/**']
|
|
16
|
+
pull_request:
|
|
17
|
+
|
|
18
|
+
concurrency:
|
|
19
|
+
group: tests-${{ github.ref }}
|
|
20
|
+
cancel-in-progress: true
|
|
21
|
+
|
|
22
|
+
env:
|
|
23
|
+
TOOLCHAIN_VERSION: 0.10.12
|
|
24
|
+
|
|
25
|
+
jobs:
|
|
26
|
+
suite:
|
|
27
|
+
runs-on: ubuntu-latest
|
|
28
|
+
timeout-minutes: 25
|
|
29
|
+
steps:
|
|
30
|
+
- uses: actions/checkout@v4
|
|
31
|
+
- uses: actions/setup-node@v4
|
|
32
|
+
with:
|
|
33
|
+
node-version: 22
|
|
34
|
+
- name: Install published toolchain (mufl + sdk + broker)
|
|
35
|
+
run: |
|
|
36
|
+
mkdir -p /tmp/toolchain && cd /tmp/toolchain
|
|
37
|
+
npm init -y > /dev/null
|
|
38
|
+
npm i --no-audit --no-fund \
|
|
39
|
+
"@adapt-toolkit/mufl@${TOOLCHAIN_VERSION}" \
|
|
40
|
+
"@adapt-toolkit/sdk@${TOOLCHAIN_VERSION}" \
|
|
41
|
+
"@adapt-toolkit/broker@${TOOLCHAIN_VERSION}"
|
|
42
|
+
- name: Build the adapt-checkout shim over the npm mufl package
|
|
43
|
+
run: |
|
|
44
|
+
M=/tmp/toolchain/node_modules/@adapt-toolkit/mufl
|
|
45
|
+
S=/tmp/tk-shim
|
|
46
|
+
mkdir -p "$S/build.linux.release"
|
|
47
|
+
ln -s "$M/prebuilds/linux-x64/mufl-compile" "$S/build.linux.release/mufl-compile"
|
|
48
|
+
for d in mufl_stdlib meta transactions; do ln -s "$M/$d" "$S/$d"; done
|
|
49
|
+
- name: Run the migration suite (incl. the v0-blob A3 gate)
|
|
50
|
+
run: |
|
|
51
|
+
export ADAPT_TOOLKIT=/tmp/tk-shim
|
|
52
|
+
export OURS_SDK_NODE_MODULES=/tmp/toolchain/node_modules
|
|
53
|
+
export DEV_BROKER=/tmp/toolchain/node_modules/@adapt-toolkit/broker/dist/cli.js
|
|
54
|
+
bash tests/run_mig.sh
|
|
55
|
+
- name: Run the core loopback suite
|
|
56
|
+
run: |
|
|
57
|
+
export ADAPT_TOOLKIT=/tmp/tk-shim
|
|
58
|
+
export OURS_SDK_NODE_MODULES=/tmp/toolchain/node_modules
|
|
59
|
+
export DEV_BROKER=/tmp/toolchain/node_modules/@adapt-toolkit/broker/dist/cli.js
|
|
60
|
+
bash tests/run.sh
|
|
61
|
+
- name: Run the notifications suite
|
|
62
|
+
run: |
|
|
63
|
+
export ADAPT_TOOLKIT=/tmp/tk-shim
|
|
64
|
+
export OURS_SDK_NODE_MODULES=/tmp/toolchain/node_modules
|
|
65
|
+
export DEV_BROKER=/tmp/toolchain/node_modules/@adapt-toolkit/broker/dist/cli.js
|
|
66
|
+
bash tests/run_notif.sh
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Commercial Licence
|
|
2
|
+
|
|
3
|
+
ours.network is released under the [Functional Source License, Version 1.1 (FSL-1.1-Apache-2.0)](./LICENSE). The FSL lets you use, copy, modify, and redistribute the software **for any purpose except a Competing Use** — broadly, making the software available to others in a commercial product or service that substitutes for ours.network, substitutes for another product or service Adapt Framework Solutions Ltd offers using the software, or provides the same or substantially similar functionality. Two years after each release is published, that version additionally becomes available under Apache 2.0.
|
|
4
|
+
|
|
5
|
+
If you want to use ours.network in a way the FSL does not permit — in particular a **Competing Use** — you need a separate **commercial licence** from **Adapt Framework Solutions Ltd**, the owner and licensor of ours.network.
|
|
6
|
+
|
|
7
|
+
## When you need a commercial licence
|
|
8
|
+
|
|
9
|
+
You need a commercial licence if, for example, you intend to:
|
|
10
|
+
|
|
11
|
+
- offer a hosted or managed service that provides the same or substantially similar functionality as ours.network;
|
|
12
|
+
- embed ours.network in a commercial product or service that competes with ours.network, or with another product or service Adapt Framework Solutions Ltd offers using the software; or
|
|
13
|
+
- otherwise make a Competing Use as defined in the [LICENSE](./LICENSE).
|
|
14
|
+
|
|
15
|
+
You do **not** need a commercial licence for a Permitted Purpose under the FSL — including your internal use and access, non-commercial research or education, or professional services you provide to a licensee using the software under the FSL. When in doubt, ask.
|
|
16
|
+
|
|
17
|
+
## How to obtain one
|
|
18
|
+
|
|
19
|
+
Contact Adapt Framework Solutions Ltd: **license@adaptframework.solutions**
|
|
20
|
+
|
|
21
|
+
Please include a short description of your intended use so we can propose suitable terms.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
Note: ours.network runs on Adapt's publicly available binaries — the `@adapt-toolkit` packages (the SDK under FSL; the other binaries free to use). Adapt's own source code (its C++ core) is not open yet — it will be opened later.
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
# COMPATIBILITY — the versioned type registry (core 0.5.0)
|
|
2
|
+
|
|
3
|
+
This document is **binding on every core change**. It declares the oldest peer this core
|
|
4
|
+
interoperates with, the registry of versioned wire types, the discriminator rules, and the
|
|
5
|
+
PR checklist a wire change must satisfy. Companion mechanism doc:
|
|
6
|
+
`docs/how-it-works/versioning.md`. The registry itself lives in **`a2a_versions.mm`**.
|
|
7
|
+
|
|
8
|
+
## Invariant
|
|
9
|
+
|
|
10
|
+
> **OLD PEERS NEVER CRASH.** Any payload a peer ≥ OSP sends is either dispatched to a typed
|
|
11
|
+
> per-version branch, or converted into a **first-class error value returned as data**
|
|
12
|
+
> (`a2a_versions::version_error_t`) — never a raw `EVAL_ERROR` escaping to the client.
|
|
13
|
+
> Crypto/tamper failures and identity-verification failures remain hard aborts by design.
|
|
14
|
+
|
|
15
|
+
## OSP — oldest supported peer
|
|
16
|
+
|
|
17
|
+
**OSP = core 0.2.0** (`faa2b52`, the deployed ours-mcp pin) → version floor
|
|
18
|
+
`a2a_versions::min_wire_version = 2`.
|
|
19
|
+
|
|
20
|
+
Raising the OSP is an **owner decision recorded here**: drop the dead `v*_t` types from the
|
|
21
|
+
unions, delete their corpus fixtures (a visible, reviewed act), and update this section.
|
|
22
|
+
|
|
23
|
+
## The wire version id (`$pv`)
|
|
24
|
+
|
|
25
|
+
- `wire_version = 8` (minor-version ints: 0.5.0 stamped `$pv -> 5`; 0.7.x stamps `7` — the
|
|
26
|
+
rcp/receipts surface registered in 0.7 warranted the bump; the initial 0.7.0 under-bump left
|
|
27
|
+
pre-receipts contacts permanently receipt-gated, the fixed single-tick bug; 0.8.0 stamps `8` —
|
|
28
|
+
the **e2e** signed-message surface registered in 0.8). Monotone; bump **only** when a wire
|
|
29
|
+
surface registers a new versioned type — not on every release.
|
|
30
|
+
- Stamped on every core-originated send: cleartext `$targ` envelopes **and** inside the
|
|
31
|
+
boxed identity-bundle payloads (invite legs 1/3, restore legs 1/2).
|
|
32
|
+
- Absence ⇒ pre-0.5 peer; the registry's per-surface **shape-inference rule** applies.
|
|
33
|
+
- A **mistyped** `$pv` (non-int) is treated as unstamped — reading the discriminator can
|
|
34
|
+
never abort.
|
|
35
|
+
- `$pv` is peer-asserted metadata riding authenticated channels: it gates parsing branches,
|
|
36
|
+
send-side feature selection, and diagnostics — **NEVER authz** (REG-6). Signed-artifact
|
|
37
|
+
`$version` ints (fail-closed) remain the only security-relevant version checks.
|
|
38
|
+
- Passive learning: `a2a_messaging::contact_pv` (cid → last-seen dialect; 0 = pre-0.5) and
|
|
39
|
+
`contact_caps` (cid → advertised capability ids), learned on invite/restore legs and from
|
|
40
|
+
stamped `$pv` on message/file traffic (an *unstamped* message never overwrites the more
|
|
41
|
+
precise invite-time inference). Both maps are additive in the export blob, guarded on
|
|
42
|
+
import.
|
|
43
|
+
- **Refresh scope (by design):** ordinary message/file traffic refreshes **`$pv` only** —
|
|
44
|
+
`$caps` refreshes solely via the bundle legs (invite redeem / contact restore) or a future
|
|
45
|
+
daemon-driven `get_manifest` pull (backlog); it is deliberately NOT piggybacked on every
|
|
46
|
+
message (wire cost). Consequence: a peer that upgrades and then only sends ordinary
|
|
47
|
+
messages is re-learned as `contact_pv = 5` with stale/absent caps — **benign** under the
|
|
48
|
+
fail-open CAP-1 gate (absent/empty caps pass). Learning is per-contact lazy; there is no
|
|
49
|
+
bulk re-sync. Monotonicity: unstamped traffic writes nothing, and a caps entry is never
|
|
50
|
+
downgraded to empty — only replaced by a newer non-empty advertisement; `contact_pv`
|
|
51
|
+
itself is last-*stamped*-wins so an honest software downgrade is re-learned (a forged
|
|
52
|
+
lower `$pv` only degrades the forger's own UX — REG-6).
|
|
53
|
+
|
|
54
|
+
## Registry rules (REG-1…6)
|
|
55
|
+
|
|
56
|
+
- **REG-1** — every wire-visible input surface has a registry entry; a never-changed surface
|
|
57
|
+
registers a single version (pre-wiring the change procedure).
|
|
58
|
+
- **REG-2** — a wire shape change = registering a **new** `v*_t` beside the frozen old ones
|
|
59
|
+
(shipped versioned types are historical facts, never mutated). Union + dispatch gain one
|
|
60
|
+
branch; reviewers see the whole compat surface in the diff.
|
|
61
|
+
- **REG-3** — the handler accepts the union of **all** registered versions ≥ OSP. Dropping a
|
|
62
|
+
version from the union = an OSP raise (owner decision, recorded here).
|
|
63
|
+
- **REG-4 (dispatch-then-narrow)** — dispatch reads the discriminator off the RAW value and
|
|
64
|
+
exact-casts to the matched version's type. **Never** cast-to-union as the selector
|
|
65
|
+
(disjunction casts pick alternatives in canonical — not declaration — order and rebuild/
|
|
66
|
+
strip; pinned by `tests/mufl_semantics/`). A `$pv` **newer** than the newest registered
|
|
67
|
+
version narrows as the newest (class-A additions are strippable by construction).
|
|
68
|
+
- **REG-5 (safety net)** — below the registry, display/UX-class optional fields keep the
|
|
69
|
+
`opt_*` NIL-tolerant read idiom (`a2a_versions::opt_str/opt_int/opt_bool`) as defense in
|
|
70
|
+
depth. Review rule: **any new `safe` on wire data must be inside a registry
|
|
71
|
+
`narrow`/branch or an `opt_*` call.**
|
|
72
|
+
- **REG-6** — `$pv`/`$caps` never gate authorization.
|
|
73
|
+
|
|
74
|
+
## Error-as-data (`version_error_t`)
|
|
75
|
+
|
|
76
|
+
A below-floor or unrecognized payload produces, **as data** (never an abort):
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
version_error_t: ($code, $surface, $message, $peer_version, $min_supported, $max_supported)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Stable `$code` values (wire contract):
|
|
83
|
+
|
|
84
|
+
| code | meaning |
|
|
85
|
+
|---|---|
|
|
86
|
+
| `peer_version_unsupported` | peer dialect below `min_wire_version` (too old) |
|
|
87
|
+
| `payload_shape_unrecognized` | payload matches no registered version ≥ floor |
|
|
88
|
+
|
|
89
|
+
On async inbound surfaces the handler early-returns `transaction::success` carrying a
|
|
90
|
+
`_notify_agent` event **before any state write**:
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
($event -> $protocol_error, $context -> $invite_redeem | $invite_complete | $contact_restore,
|
|
94
|
+
$message -> <context-specific, render-ready>, $error -> version_error_t,
|
|
95
|
+
$peer_cid -> …, $invite_id -> … when applicable)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Consumer obligation: the MCP daemon / control-plane frontend surface `$message` (and may
|
|
99
|
+
resolve `$error` for details). **Client-side rendering is a separate follow-up task**; the
|
|
100
|
+
core guarantees the shape above.
|
|
101
|
+
|
|
102
|
+
Owner-specified UX (implemented): a version-incompatible **invite second phase** does NOT
|
|
103
|
+
consume the invite — after the peer updates, the **same invite** redeems successfully. The
|
|
104
|
+
inviter's message says exactly that.
|
|
105
|
+
|
|
106
|
+
The CAP-1 denial (below) uses the sibling shape
|
|
107
|
+
`($ok -> FALSE, $error -> ($code -> "capability_not_advertised", $cap, $message, $peer_cid))`
|
|
108
|
+
returned as the transaction's data result.
|
|
109
|
+
|
|
110
|
+
### Abort-free classification (M1) and its documented residual
|
|
111
|
+
|
|
112
|
+
`try_narrow_*` pre-checks every **non-nullable** field the exact cast reads: presence AND
|
|
113
|
+
runtime domain via `_typeof` (str→`STRING`, int→`INTEGER`; `global_id` rides `STRING`).
|
|
114
|
+
Nullable fields (`bin+`, `str[]+`) are exempt (absent ⇒ NIL passes). Residual, accepted:
|
|
115
|
+
`safe global_id` also hex-validates, so a STRING-but-not-valid-hex id still aborts inside
|
|
116
|
+
the exact cast — no shipped sender can produce that; reaching it requires a hostile
|
|
117
|
+
hand-crafted box, which is the malformed/tamper class where an abort is correct.
|
|
118
|
+
|
|
119
|
+
## Registry index (0.5.0)
|
|
120
|
+
|
|
121
|
+
| Surface | Registry | Registered versions | Discriminator (pre-`$pv` inference) |
|
|
122
|
+
|---|---|---|---|
|
|
123
|
+
| leg-1 boxed identity bundle (`submit_invite_response`) | **sir** | v2 / v3 (+`$name`) / v5 (+`$pv`,`$caps`) | `$pv`; else `$name` present ⇒ 3, else 2. `$pv` 3..4 ⇒ v3 (0.4.x never shipped; wire-identical to 0.3), ≥5 ⇒ v5 |
|
|
124
|
+
| leg-3 boxed identity bundle (`complete_invite`) | **cin** | v2 / v5 (+`$pv`,`$caps`; never carried `$name`) | `$pv`; else 2 |
|
|
125
|
+
| restore legs 1/2 boxed bundles (`submit_restore_response`, `complete_restore`) | **rst** | v2 / v5 (+`$pv`,`$caps`) | `$pv`; else 2 |
|
|
126
|
+
| legacy `accept_contact` args | **acc** | v2 / v3 (+`$joiner_name`) | `$pv`; else `$joiner_name` present ⇒ 3, else 2. Path slated for class-C removal at the next OSP raise |
|
|
127
|
+
| `receive_message` `$targ` | **rmsg** | single version (+`$pv` stamp in 0.5.0) | `$pv`; else 2 |
|
|
128
|
+
| `receive_file` `$targ` | **rfil** | single version (+`$pv` stamp in 0.5.0) | `$pv`; else 2 |
|
|
129
|
+
| `receive_receipt` `$targ` (0.7.0) | **rcp** | single version (v1: `$kind`, `$wire_ids`, `$date+`, `$pv+`) | `$pv`; else 7 (surface cannot predate 0.7). Reachable only behind positive `core.receipts.*` caps |
|
|
130
|
+
| `e2e_signed_message` variant (0.8.0) | **e2e** | single version (v1: `$e2e_envelope` = `t_e2e_envelope`(`$session_id`,`$olm_type`,`$ciphertext`,`$pv+`), `$emsignature`) | inner `$e2e_envelope.$pv`; else 8 (surface cannot predate 0.8). Reachable only behind the `core.e2e` cap + AD v2 bundle; decode branch keys on the `$e2e_envelope` marker |
|
|
131
|
+
|
|
132
|
+
**Deferred surfaces** (tolerant field-by-field readers today; register on their first shape
|
|
133
|
+
change, or when REG-1 is extended repo-wide — owner question SPEC Q9): invite/restore
|
|
134
|
+
cleartext envelopes (`{$invite_id/$rid, $epk, $v, $data}` — now `$pv`-stamped on send),
|
|
135
|
+
`ingest_connect_descriptor`, `enroll_delegated_node`, `control_message` envelope,
|
|
136
|
+
monitoring copies / `push_to_cp` pushes (generic pass-through `$targ`, not stamped),
|
|
137
|
+
`notify_*` service surfaces (all `$pv`-stamped on send), signed artifacts (class D,
|
|
138
|
+
fail-closed, unchanged), export/import blob (`core_format_version`, INV-C3).
|
|
139
|
+
|
|
140
|
+
## Capability piggyback + CAP-1
|
|
141
|
+
|
|
142
|
+
The v5 bundle payloads carry `$caps -> str[]` — the sender's capability **ids** (from
|
|
143
|
+
`a2a_capabilities::self_cap_ids`, captured at `init` from `$supported`; empty for an app
|
|
144
|
+
that never wired capabilities). Learned into `contact_caps`.
|
|
145
|
+
|
|
146
|
+
**CAP-1 gate** (at the notify client sends `notify_register` / `send_notification`): deny —
|
|
147
|
+
**as data, degrade never abort** — only on **positive evidence**: a non-empty learned caps
|
|
148
|
+
set that lacks `core.notifications`. Unknown / absent / empty caps pass (pre-0.5 peers and
|
|
149
|
+
pre-0.5-established contacts keep working). Owner-approved fail-open interpretation.
|
|
150
|
+
|
|
151
|
+
## Wire-change taxonomy
|
|
152
|
+
|
|
153
|
+
| Class | What | Procedure |
|
|
154
|
+
|---|---|---|
|
|
155
|
+
| **A** | add an optional field to a tolerant surface | register `v<next>_t` (REG-2); union + dispatch gain a branch; corpus proves OSP unaffected. MINOR |
|
|
156
|
+
| **B** | new transaction (new inbound name) | new registry, single version; sends gated by CAP-1/`$pv`. MINOR |
|
|
157
|
+
| **C** | change/remove a field, change semantics | BREAKING: parallel transaction (class B) or new registered version with a dual-accept window; old version leaves the union only on an OSP raise. MAJOR |
|
|
158
|
+
| **D** | evolve a signed artifact | mint `vN+1` core metadef beside `vN`; verifiers accept an explicit version set; unknown version **fail-closed** (authz). Never mutate a signed shape |
|
|
159
|
+
|
|
160
|
+
## Message receipts (core 0.7.0) — capability-gated, fail-closed
|
|
161
|
+
|
|
162
|
+
Two protocol events on the recipient produce two pings to the message sender, both carried
|
|
163
|
+
by ONE new class-B transaction `::a2a_messaging::receive_receipt`
|
|
164
|
+
(`$kind "delivered"|"read"`, `$wire_ids str[]` — the shared message+file namespace, `$date+`,
|
|
165
|
+
`$pv+`): **delivered** fires atomically inside the accepted
|
|
166
|
+
`receive_message`/`receive_file` transaction (app-hook abort = no receipt); **read** fires on
|
|
167
|
+
the consumer's get/mark-read path via `read_receipt_actions` (readonly trns cannot send, so
|
|
168
|
+
the unread→read MARK is the read event — exact-once for free).
|
|
169
|
+
|
|
170
|
+
**Gate (hybrid since the caps-relearn fix):** caps are exchanged only on invite/restore
|
|
171
|
+
bundle legs and never re-negotiate on app update, so an EXPLICIT caps opinion (any
|
|
172
|
+
`core.receipts.*` id in the learned set) is followed strictly (receive ⇒ send; opinion
|
|
173
|
+
without receive ⇒ opt-out), while a caps-silent peer with learned dialect `pv >= 7` gets
|
|
174
|
+
`receive` IMPLIED — `contact_pv` re-learns from every stamped ordinary message, so two
|
|
175
|
+
upgraded peers self-heal on their first exchange, no re-pair. Old peers (`pv < 7`) stay
|
|
176
|
+
silent. Same hybrid drives `receipt_expectation`.
|
|
177
|
+
|
|
178
|
+
Capabilities (2 flat ids in `a2a_capabilities`, advertised via the new **`$advertise`** init
|
|
179
|
+
param — protocol-surface ids with no control verbs, so the `$supported`
|
|
180
|
+
declared-implies-implemented handler guard doesn't apply to them):
|
|
181
|
+
`core.receipts.emit` ("I will emit both kinds") and `core.receipts.receive` ("send me
|
|
182
|
+
yours"). Delivery-vs-read is wire metadata, not a capability split.
|
|
183
|
+
|
|
184
|
+
**Gate polarity — deliberately the OPPOSITE of CAP-1:** receipts fail **CLOSED** on
|
|
185
|
+
unknown/absent caps. Emit iff self advertises `emit` AND the peer POSITIVELY advertises
|
|
186
|
+
`receive` in learned `contact_caps`. Old clients advertise neither id ⇒ nothing is ever sent
|
|
187
|
+
to them (nothing they can't parse) and nothing is expected from them — zero transaction
|
|
188
|
+
failures both directions, by construction. Sender-side state is DERIVED
|
|
189
|
+
(`receipt_expectation`: "expected" iff the peer advertises `emit`, else "unknown" — absence
|
|
190
|
+
of a receipt is NEVER failure; no timeout state in core). Ingest is tolerant and never
|
|
191
|
+
load-bearing: unknown `$kind` = future receipt kind (ignore-success), malformed shapes are
|
|
192
|
+
dropped abort-free (rcp M1 checks incl. the list-domain guard), unknown senders get silent
|
|
193
|
+
success, and no receipt is ever emitted for a receipt. Consumer hook
|
|
194
|
+
(`on_receipt_received`, optional, default no-op) contract: application is MONOTONIC per
|
|
195
|
+
(peer, wire_id) on `unknown < sent < delivered < read`.
|
|
196
|
+
|
|
197
|
+
## Golden-wire corpus (release gate)
|
|
198
|
+
|
|
199
|
+
One fixture per registered version per registry, built as the **exact wire shape** that
|
|
200
|
+
version's sender emits (fixtures-as-code in `tests/test_actor.mu::qa_corpus_narrow` — the
|
|
201
|
+
payloads carry real ids + a real AD, which JSON files cannot encode), replayed through
|
|
202
|
+
`try_narrow_*`; the driver asserts the branch taken, the error-as-data classifications
|
|
203
|
+
(below-floor, unrecognized, mistyped fields), forward-compat (`$pv=7`⇒newest, `$pv=4`⇒v3),
|
|
204
|
+
and that the strict `narrow_*` aborts with the stable message.
|
|
205
|
+
|
|
206
|
+
Run: `tests/run_corpus.sh` (fast) — also exercised by the full suite `tests/run.sh`
|
|
207
|
+
(V-series: cross-version leg-1 end-to-end, Additions A/B, CAP-1, `$pv` learning) and
|
|
208
|
+
`tests/mufl_semantics/run.sh` (toolchain-behavior pins; verified on the **vendored mufl
|
|
209
|
+
0.8.0**). **A release is green only if every registered version parses and dispatches to
|
|
210
|
+
its branch.** Raising the OSP deletes corpus entries deliberately.
|
|
211
|
+
|
|
212
|
+
## PR checklist — any wire change
|
|
213
|
+
|
|
214
|
+
- [ ] New `v<next>_t` metadef registered beside the frozen ones (never mutate a shipped type)
|
|
215
|
+
- [ ] Union + `versions_t` vector + `version_of`/`try_narrow` branch updated in `a2a_versions.mm`
|
|
216
|
+
- [ ] Non-nullable fields of the new type added to the `_typeof` shape check (M1)
|
|
217
|
+
- [ ] Corpus fixture added (`qa_corpus_narrow`) + driver assertion (`tests/corpus.mjs`)
|
|
218
|
+
- [ ] `wire_version` bumped iff the surface's shape changed; pv↔core table updated in `docs/how-it-works/versioning.md`
|
|
219
|
+
- [ ] Release note carries a **Wire delta** section (fields added, surfaces, OSP impact)
|
|
220
|
+
- [ ] `version.mm` bumped
|
|
221
|
+
- [ ] Registry index table above updated
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Contributing to ours.network
|
|
2
|
+
|
|
3
|
+
Thank you for your interest in ours.network. We welcome bug reports, feature discussion, documentation fixes, and code contributions.
|
|
4
|
+
|
|
5
|
+
## Before you start
|
|
6
|
+
|
|
7
|
+
- **Bug reports and ideas:** open an issue. Please include reproduction steps and your environment.
|
|
8
|
+
- **Security issues:** do **not** open a public issue — see [SECURITY.md](./SECURITY.md).
|
|
9
|
+
- **Code contributions:** require a signed Contributor Licence Agreement (CLA) — see below. Until the CLA process is live, we are accepting **issues and feedback only**, not pull requests.
|
|
10
|
+
|
|
11
|
+
## The CLA, and why we require it
|
|
12
|
+
|
|
13
|
+
ours.network is licensed under the Functional Source License (FSL-1.1-Apache-2.0): source-available today and converting to Apache 2.0 in the future, with paid commercial licences available for organisations that need terms beyond the FSL. The commercial licences are what fund full-time maintenance of this project.
|
|
14
|
+
|
|
15
|
+
For that model to work, Adapt Framework Solutions Ltd must hold sufficient rights in the entire codebase, including external contributions. So before we can merge your first pull request, we ask you to sign our CLA. **You keep ownership of your contribution**; you grant us a broad licence to it, including the right to include it in commercially licensed versions.
|
|
16
|
+
|
|
17
|
+
We know CLAs are sometimes criticised as one-sided ("you can relicense our work; we can't relicense yours"). That asymmetry is real, and this is the honest reason for it: it is what keeps the source-available version maintained. If that trade isn't acceptable to you, we completely understand — issues, reviews, and discussion are valuable contributions that need no paperwork.
|
|
18
|
+
|
|
19
|
+
## Pull request guidelines
|
|
20
|
+
|
|
21
|
+
1. Open or comment on an issue first for anything non-trivial, so we can agree the approach before you write code.
|
|
22
|
+
2. Keep PRs focused — one change per PR.
|
|
23
|
+
3. Include tests for behavioural changes and update documentation affected by your change.
|
|
24
|
+
4. **Wire changes** (anything a peer sends or receives) must follow the versioned
|
|
25
|
+
type registry rules and PR checklist in [COMPATIBILITY.md](./COMPATIBILITY.md) —
|
|
26
|
+
register a new versioned type, add a corpus fixture, note the Wire delta, bump
|
|
27
|
+
`version.mm`.
|
|
28
|
+
5. Sign the CLA when prompted by the CLA bot (first PR only).
|
|
29
|
+
6. Use clear commit messages; reference the issue number.
|
|
30
|
+
|
|
31
|
+
## Code of conduct
|
|
32
|
+
|
|
33
|
+
Be kind, be constructive, assume good faith. Maintainers may close issues or PRs that don't follow these guidelines.
|
|
34
|
+
|
|
35
|
+
## Licence of contributions
|
|
36
|
+
|
|
37
|
+
By contributing, you agree that your contributions are provided under the terms of the CLA and will be distributed under the project's licences (the Functional Source License, FSL-1.1-Apache-2.0, and the Company's commercial licences).
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Functional Source License, Version 1.1, Apache 2.0 Future License
|
|
2
|
+
|
|
3
|
+
## Abbreviation
|
|
4
|
+
|
|
5
|
+
FSL-1.1-Apache-2.0
|
|
6
|
+
|
|
7
|
+
## Notice
|
|
8
|
+
|
|
9
|
+
Copyright 2026 Adapt Framework Solutions Ltd
|
|
10
|
+
|
|
11
|
+
## Terms and Conditions
|
|
12
|
+
|
|
13
|
+
### Licensor ("We")
|
|
14
|
+
|
|
15
|
+
The party offering the Software under these Terms and Conditions.
|
|
16
|
+
|
|
17
|
+
### The Software
|
|
18
|
+
|
|
19
|
+
The "Software" is each version of the software that we make available under
|
|
20
|
+
these Terms and Conditions, as indicated by our inclusion of these Terms and
|
|
21
|
+
Conditions with the Software.
|
|
22
|
+
|
|
23
|
+
### License Grant
|
|
24
|
+
|
|
25
|
+
Subject to your compliance with this License Grant and the Patents,
|
|
26
|
+
Redistribution and Trademark clauses below, we hereby grant you the right to use,
|
|
27
|
+
copy, modify, create derivative works, publicly perform, publicly display and
|
|
28
|
+
redistribute the Software for any Permitted Purpose identified below.
|
|
29
|
+
|
|
30
|
+
### Permitted Purpose
|
|
31
|
+
|
|
32
|
+
A Permitted Purpose is any purpose other than a Competing Use. A Competing Use
|
|
33
|
+
means making the Software available to others in a commercial product or service
|
|
34
|
+
that:
|
|
35
|
+
|
|
36
|
+
1. substitutes for the Software;
|
|
37
|
+
|
|
38
|
+
2. substitutes for any other product or service we offer using the Software that
|
|
39
|
+
exists as of the date we make the Software available; or
|
|
40
|
+
|
|
41
|
+
3. offers the same or substantially similar functionality as the Software.
|
|
42
|
+
|
|
43
|
+
Permitted Purposes specifically include using the Software:
|
|
44
|
+
|
|
45
|
+
1. for your internal use and access;
|
|
46
|
+
|
|
47
|
+
2. for non-commercial education;
|
|
48
|
+
|
|
49
|
+
3. for non-commercial research; and
|
|
50
|
+
|
|
51
|
+
4. in connection with professional services that you provide to a licensee using
|
|
52
|
+
the Software in accordance with these Terms and Conditions.
|
|
53
|
+
|
|
54
|
+
### Patents
|
|
55
|
+
|
|
56
|
+
To the extent your use for a Permitted Purpose would necessarily infringe our
|
|
57
|
+
patents, the license grant above includes a license under our patents. If you
|
|
58
|
+
make a claim against any party that the Software infringes or contributes to the
|
|
59
|
+
infringement of any patent, then your patent license to the Software ends
|
|
60
|
+
immediately.
|
|
61
|
+
|
|
62
|
+
### Redistribution
|
|
63
|
+
|
|
64
|
+
The Terms and Conditions apply to all copies, modifications and derivatives of
|
|
65
|
+
the Software.
|
|
66
|
+
|
|
67
|
+
If you redistribute any copies, modifications or derivatives of the Software, you
|
|
68
|
+
must include a copy of or a link to these Terms and Conditions and not remove any
|
|
69
|
+
copyright notices provided in or with the Software.
|
|
70
|
+
|
|
71
|
+
### Disclaimer
|
|
72
|
+
|
|
73
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, INCLUDING
|
|
74
|
+
WITHOUT LIMITATION WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
|
75
|
+
PURPOSE, NON-INFRINGEMENT, OR THAT THE SOFTWARE IS FREE OF DEFECTS. IN NO EVENT
|
|
76
|
+
WILL WE HAVE ANY LIABILITY TO YOU ARISING OUT OF OR RELATED TO THE SOFTWARE,
|
|
77
|
+
INCLUDING INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES, EVEN IF WE HAVE
|
|
78
|
+
BEEN INFORMED OF THEIR POSSIBILITY IN ADVANCE.
|
|
79
|
+
|
|
80
|
+
### Grant of Future License
|
|
81
|
+
|
|
82
|
+
We hereby irrevocably grant you an additional license to use the Software under
|
|
83
|
+
the Apache License, Version 2.0 that is effective on the second anniversary of
|
|
84
|
+
the date we make the Software available. On or after that date, you may use the
|
|
85
|
+
Software under the Apache License, Version 2.0, in which case the following will
|
|
86
|
+
apply:
|
|
87
|
+
|
|
88
|
+
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
|
89
|
+
this file except in compliance with the License.
|
|
90
|
+
|
|
91
|
+
You may obtain a copy of the License at
|
|
92
|
+
|
|
93
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
94
|
+
|
|
95
|
+
Unless required by applicable law or agreed to in writing, software distributed
|
|
96
|
+
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
97
|
+
CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
98
|
+
specific language governing permissions and limitations under the License.
|