mirror of
https://github.com/Such-Software/adaptive-multi-protocol-gateway.git
synced 2026-10-17 07:31:32 +02:00
Add interaction capability policy docs
This commit is contained in:
@@ -79,6 +79,7 @@ internal even when the public site is available on Tor or I2P.
|
|||||||
- [Configuration](docs/configuration.md)
|
- [Configuration](docs/configuration.md)
|
||||||
- [Daemon management](docs/daemon-management.md)
|
- [Daemon management](docs/daemon-management.md)
|
||||||
- [Fixture manifests](docs/fixture-manifests.md)
|
- [Fixture manifests](docs/fixture-manifests.md)
|
||||||
|
- [Interaction capabilities](docs/interaction-capabilities.md)
|
||||||
- [Interactive applications](docs/interactive-apps.md)
|
- [Interactive applications](docs/interactive-apps.md)
|
||||||
- [Wownero integration](docs/wownero-integration.md)
|
- [Wownero integration](docs/wownero-integration.md)
|
||||||
- [Autodocs and drift gates](docs/autodocs.md)
|
- [Autodocs and drift gates](docs/autodocs.md)
|
||||||
|
|||||||
+55
-1
@@ -2,7 +2,15 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from .metadata import CONFIG_FIELDS, DAEMON_ADAPTERS, RENDER_PROFILES
|
from .metadata import (
|
||||||
|
CONFIG_FIELDS,
|
||||||
|
DAEMON_ADAPTERS,
|
||||||
|
IDENTITY_ADAPTERS,
|
||||||
|
INTERACTION_TIERS,
|
||||||
|
PAYMENT_ADAPTERS,
|
||||||
|
RENDER_PROFILES,
|
||||||
|
TRANSPORT_INTERACTION_CAPABILITIES,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
GENERATED_DIR = Path("docs/generated")
|
GENERATED_DIR = Path("docs/generated")
|
||||||
@@ -12,6 +20,7 @@ def generate_docs(root: Path, *, check: bool = False) -> list[Path]:
|
|||||||
docs = {
|
docs = {
|
||||||
GENERATED_DIR / "config-schema.md": _config_schema_doc(),
|
GENERATED_DIR / "config-schema.md": _config_schema_doc(),
|
||||||
GENERATED_DIR / "daemon-adapters.md": _daemon_adapters_doc(),
|
GENERATED_DIR / "daemon-adapters.md": _daemon_adapters_doc(),
|
||||||
|
GENERATED_DIR / "interaction-capabilities.md": _interaction_capabilities_doc(),
|
||||||
GENERATED_DIR / "render-profiles.md": _render_profiles_doc(),
|
GENERATED_DIR / "render-profiles.md": _render_profiles_doc(),
|
||||||
}
|
}
|
||||||
changed: list[Path] = []
|
changed: list[Path] = []
|
||||||
@@ -83,3 +92,48 @@ def _render_profiles_doc() -> str:
|
|||||||
sections.append(f"- {default}")
|
sections.append(f"- {default}")
|
||||||
sections.append("")
|
sections.append("")
|
||||||
return "\n".join(sections)
|
return "\n".join(sections)
|
||||||
|
|
||||||
|
|
||||||
|
def _interaction_capabilities_doc() -> str:
|
||||||
|
sections = [_header("Generated Interaction Capabilities")]
|
||||||
|
sections.append("## Tiers\n")
|
||||||
|
sections.append("| Tier | Summary | Examples | Notes |")
|
||||||
|
sections.append("| --- | --- | --- | --- |")
|
||||||
|
for tier in INTERACTION_TIERS:
|
||||||
|
sections.append(
|
||||||
|
f"| `{tier.name}` | {tier.summary} | {', '.join(tier.examples)} | "
|
||||||
|
f"{' '.join(tier.notes)} |"
|
||||||
|
)
|
||||||
|
sections.append("")
|
||||||
|
|
||||||
|
sections.append("## Identity Adapters\n")
|
||||||
|
sections.append("| Adapter | Status | Transports | Notes |")
|
||||||
|
sections.append("| --- | --- | --- | --- |")
|
||||||
|
for adapter in IDENTITY_ADAPTERS:
|
||||||
|
sections.append(
|
||||||
|
f"| `{adapter.name}` | `{adapter.status}` | {', '.join(adapter.transports)} | "
|
||||||
|
f"{' '.join(adapter.notes)} |"
|
||||||
|
)
|
||||||
|
sections.append("")
|
||||||
|
|
||||||
|
sections.append("## Payment Adapters\n")
|
||||||
|
sections.append("| Adapter | Status | Transports | Notes |")
|
||||||
|
sections.append("| --- | --- | --- | --- |")
|
||||||
|
for adapter in PAYMENT_ADAPTERS:
|
||||||
|
sections.append(
|
||||||
|
f"| `{adapter.name}` | `{adapter.status}` | {', '.join(adapter.transports)} | "
|
||||||
|
f"{' '.join(adapter.notes)} |"
|
||||||
|
)
|
||||||
|
sections.append("")
|
||||||
|
|
||||||
|
sections.append("## Transport Limits\n")
|
||||||
|
sections.append("| Transport | Public Max Tier | Identity | Payments | Realtime | Notes |")
|
||||||
|
sections.append("| --- | --- | --- | --- | --- | --- |")
|
||||||
|
for capability in TRANSPORT_INTERACTION_CAPABILITIES:
|
||||||
|
sections.append(
|
||||||
|
f"| `{capability.transport}` | `{capability.public_max_tier}` | "
|
||||||
|
f"{capability.identity} | {capability.payments} | {capability.realtime} | "
|
||||||
|
f"{' '.join(capability.notes)} |"
|
||||||
|
)
|
||||||
|
sections.append("")
|
||||||
|
return "\n".join(sections)
|
||||||
|
|||||||
@@ -33,6 +33,40 @@ class DaemonAdapter:
|
|||||||
notes: tuple[str, ...]
|
notes: tuple[str, ...]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class InteractionTier:
|
||||||
|
name: str
|
||||||
|
summary: str
|
||||||
|
examples: tuple[str, ...]
|
||||||
|
notes: tuple[str, ...]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class IdentityAdapter:
|
||||||
|
name: str
|
||||||
|
status: str
|
||||||
|
transports: tuple[str, ...]
|
||||||
|
notes: tuple[str, ...]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class PaymentAdapter:
|
||||||
|
name: str
|
||||||
|
status: str
|
||||||
|
transports: tuple[str, ...]
|
||||||
|
notes: tuple[str, ...]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class TransportInteractionCapability:
|
||||||
|
transport: str
|
||||||
|
public_max_tier: str
|
||||||
|
identity: str
|
||||||
|
payments: str
|
||||||
|
realtime: str
|
||||||
|
notes: tuple[str, ...]
|
||||||
|
|
||||||
|
|
||||||
CONFIG_FIELDS = (
|
CONFIG_FIELDS = (
|
||||||
ConfigField("site", "id", "string", True, "", "Stable site identifier used in output paths."),
|
ConfigField("site", "id", "string", True, "", "Stable site identifier used in output paths."),
|
||||||
ConfigField("site", "domain", "string", True, "", "Canonical public domain for the site."),
|
ConfigField("site", "domain", "string", True, "", "Canonical public domain for the site."),
|
||||||
@@ -57,6 +91,38 @@ CONFIG_FIELDS = (
|
|||||||
"[]",
|
"[]",
|
||||||
"Route patterns that must not be published.",
|
"Route patterns that must not be published.",
|
||||||
),
|
),
|
||||||
|
ConfigField(
|
||||||
|
"site.interactions.route",
|
||||||
|
"match",
|
||||||
|
"glob",
|
||||||
|
False,
|
||||||
|
"",
|
||||||
|
"Route pattern for an explicit interaction policy.",
|
||||||
|
),
|
||||||
|
ConfigField(
|
||||||
|
"site.interactions.route",
|
||||||
|
"tier",
|
||||||
|
"enum",
|
||||||
|
False,
|
||||||
|
"site.interactions.default_tier",
|
||||||
|
"Interaction tier for a route group.",
|
||||||
|
),
|
||||||
|
ConfigField(
|
||||||
|
"site.interactions.route",
|
||||||
|
"identity",
|
||||||
|
"enum",
|
||||||
|
False,
|
||||||
|
"none",
|
||||||
|
"Identity adapter required by a route group.",
|
||||||
|
),
|
||||||
|
ConfigField(
|
||||||
|
"site.interactions.route",
|
||||||
|
"payments",
|
||||||
|
"enum",
|
||||||
|
False,
|
||||||
|
"none",
|
||||||
|
"Payment adapter required by a route group.",
|
||||||
|
),
|
||||||
ConfigField(
|
ConfigField(
|
||||||
"site.protocols.<name>",
|
"site.protocols.<name>",
|
||||||
"enabled",
|
"enabled",
|
||||||
@@ -108,6 +174,175 @@ CONFIG_FIELDS = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
INTERACTION_TIERS = (
|
||||||
|
InteractionTier(
|
||||||
|
name="static",
|
||||||
|
summary="Rendered files only.",
|
||||||
|
examples=("documentation", "landing pages", "catalog pages"),
|
||||||
|
notes=("Works across every currently modeled transport.",),
|
||||||
|
),
|
||||||
|
InteractionTier(
|
||||||
|
name="interactive-lite",
|
||||||
|
summary="Client-visible state with deterministic or server-rendered updates.",
|
||||||
|
examples=("deterministic games", "leaderboards", "quote forms", "status lookups"),
|
||||||
|
notes=(
|
||||||
|
"Does not require accounts or payment confirmation.",
|
||||||
|
"Constrained transports may receive static snapshots or form-style actions.",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
InteractionTier(
|
||||||
|
name="identity",
|
||||||
|
summary="Authenticated sessions or signed wallet identity.",
|
||||||
|
examples=("account pages", "wallet sign-in", "claim pages"),
|
||||||
|
notes=(
|
||||||
|
"Requires explicit identity adapter selection.",
|
||||||
|
"HTTP transports can use strict cookies; wallet sign-in uses signed challenges.",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
InteractionTier(
|
||||||
|
name="transactional",
|
||||||
|
summary="Server-confirmed orders, wagers, deposits, invoices, or payment intents.",
|
||||||
|
examples=("basic stores", "paid downloads", "game entry fees", "donations"),
|
||||||
|
notes=(
|
||||||
|
"Requires explicit payment adapter selection.",
|
||||||
|
"Callbacks, webhook receivers, and ledger internals remain internal.",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
InteractionTier(
|
||||||
|
name="realtime",
|
||||||
|
summary="Live multiplayer, dashboards, websocket streams, or fast state sync.",
|
||||||
|
examples=("multiplayer games", "live markets", "operator consoles"),
|
||||||
|
notes=(
|
||||||
|
"HTTP transports only in the current model.",
|
||||||
|
"Usually clearnet or private Tor/I2P until transport-specific realtime support exists.",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
InteractionTier(
|
||||||
|
name="internal",
|
||||||
|
summary="Private/admin/worker surfaces that must not be published automatically.",
|
||||||
|
examples=("admin panels", "webhooks", "worker APIs", "health endpoints"),
|
||||||
|
notes=("Always deny by default on public outputs.",),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
IDENTITY_ADAPTERS = (
|
||||||
|
IdentityAdapter(
|
||||||
|
name="none",
|
||||||
|
status="ready",
|
||||||
|
transports=("clearnet", "tor", "i2p", "gemini", "ipfs", "reticulum"),
|
||||||
|
notes=("No account or signed identity required.",),
|
||||||
|
),
|
||||||
|
IdentityAdapter(
|
||||||
|
name="http-session",
|
||||||
|
status="planned",
|
||||||
|
transports=("clearnet", "tor", "i2p"),
|
||||||
|
notes=(
|
||||||
|
"Use HTTP-only cookies and strict transport-specific session scope.",
|
||||||
|
"Profiles must not be shared across transports.",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
IdentityAdapter(
|
||||||
|
name="siwe",
|
||||||
|
status="planned",
|
||||||
|
transports=("clearnet", "tor", "i2p"),
|
||||||
|
notes=(
|
||||||
|
"Sign-In with Ethereum style challenge/response.",
|
||||||
|
"Wallet transport availability is a browser-shell concern.",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
IdentityAdapter(
|
||||||
|
name="signed-link",
|
||||||
|
status="research",
|
||||||
|
transports=("gemini", "reticulum"),
|
||||||
|
notes=("Use only for narrow flows with short-lived, scoped capabilities.",),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
PAYMENT_ADAPTERS = (
|
||||||
|
PaymentAdapter(
|
||||||
|
name="none",
|
||||||
|
status="ready",
|
||||||
|
transports=("clearnet", "tor", "i2p", "gemini", "ipfs", "reticulum"),
|
||||||
|
notes=("No payment required.",),
|
||||||
|
),
|
||||||
|
PaymentAdapter(
|
||||||
|
name="server-invoice",
|
||||||
|
status="planned",
|
||||||
|
transports=("clearnet", "tor", "i2p"),
|
||||||
|
notes=(
|
||||||
|
"Server creates invoice or payment intent and confirms settlement.",
|
||||||
|
"Callback/webhook routes stay internal.",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
PaymentAdapter(
|
||||||
|
name="wallet-signature",
|
||||||
|
status="planned",
|
||||||
|
transports=("clearnet", "tor", "i2p"),
|
||||||
|
notes=("Browser wallet signs a request; server verifies before fulfilling.",),
|
||||||
|
),
|
||||||
|
PaymentAdapter(
|
||||||
|
name="static-instructions",
|
||||||
|
status="planned",
|
||||||
|
transports=("gemini", "ipfs", "reticulum"),
|
||||||
|
notes=("Render payment instructions or donation addresses without automatic fulfillment.",),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
TRANSPORT_INTERACTION_CAPABILITIES = (
|
||||||
|
TransportInteractionCapability(
|
||||||
|
transport="clearnet",
|
||||||
|
public_max_tier="realtime",
|
||||||
|
identity="http-session, siwe",
|
||||||
|
payments="server-invoice, wallet-signature",
|
||||||
|
realtime="yes",
|
||||||
|
notes=("Highest-fidelity browser surface.",),
|
||||||
|
),
|
||||||
|
TransportInteractionCapability(
|
||||||
|
transport="tor",
|
||||||
|
public_max_tier="transactional",
|
||||||
|
identity="http-session, siwe",
|
||||||
|
payments="server-invoice, wallet-signature",
|
||||||
|
realtime="private-only",
|
||||||
|
notes=("Prefer server-rendered flows and reduced JavaScript by default.",),
|
||||||
|
),
|
||||||
|
TransportInteractionCapability(
|
||||||
|
transport="i2p",
|
||||||
|
public_max_tier="transactional",
|
||||||
|
identity="http-session, siwe",
|
||||||
|
payments="server-invoice, wallet-signature",
|
||||||
|
realtime="private-only",
|
||||||
|
notes=("Prefer server-rendered flows and reduced JavaScript by default.",),
|
||||||
|
),
|
||||||
|
TransportInteractionCapability(
|
||||||
|
transport="gemini",
|
||||||
|
public_max_tier="interactive-lite",
|
||||||
|
identity="signed-link research",
|
||||||
|
payments="static-instructions",
|
||||||
|
realtime="no",
|
||||||
|
notes=("Use curated prompts or polling-friendly status pages.",),
|
||||||
|
),
|
||||||
|
TransportInteractionCapability(
|
||||||
|
transport="ipfs",
|
||||||
|
public_max_tier="static",
|
||||||
|
identity="none",
|
||||||
|
payments="static-instructions",
|
||||||
|
realtime="no",
|
||||||
|
notes=("Content-addressed snapshots; no server-confirmed state by default.",),
|
||||||
|
),
|
||||||
|
TransportInteractionCapability(
|
||||||
|
transport="reticulum",
|
||||||
|
public_max_tier="interactive-lite",
|
||||||
|
identity="signed-link research",
|
||||||
|
payments="static-instructions",
|
||||||
|
realtime="research",
|
||||||
|
notes=("Resilient/private routing; not an anonymity layer.",),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
RENDER_PROFILES = (
|
RENDER_PROFILES = (
|
||||||
RenderProfile(
|
RenderProfile(
|
||||||
name="clearnet",
|
name="clearnet",
|
||||||
|
|||||||
+12
-4
@@ -31,6 +31,12 @@ plan_root = "/var/lib/ampg/plans"
|
|||||||
default_tier = "static"
|
default_tier = "static"
|
||||||
deny_routes = ["/admin/*", "/internal/*", "/webhooks/*"]
|
deny_routes = ["/admin/*", "/internal/*", "/webhooks/*"]
|
||||||
|
|
||||||
|
[[site.interactions.route]]
|
||||||
|
match = "/checkout/*"
|
||||||
|
tier = "transactional"
|
||||||
|
identity = "http-session"
|
||||||
|
payments = "server-invoice"
|
||||||
|
|
||||||
[site.protocols.clearnet]
|
[site.protocols.clearnet]
|
||||||
enabled = true
|
enabled = true
|
||||||
renderer = "clearnet"
|
renderer = "clearnet"
|
||||||
@@ -151,7 +157,7 @@ upstream = "http://127.0.0.1:8000"
|
|||||||
openapi = "http://127.0.0.1:9000/openapi.json"
|
openapi = "http://127.0.0.1:9000/openapi.json"
|
||||||
|
|
||||||
[site.interactions]
|
[site.interactions]
|
||||||
default_tier = "forms"
|
default_tier = "interactive-lite"
|
||||||
session_policy = "http-only-cookie"
|
session_policy = "http-only-cookie"
|
||||||
deny_routes = ["/admin/*", "/api/internal/*", "/webhooks/*"]
|
deny_routes = ["/admin/*", "/api/internal/*", "/webhooks/*"]
|
||||||
|
|
||||||
@@ -161,11 +167,13 @@ tier = "internal"
|
|||||||
|
|
||||||
[[site.interactions.route]]
|
[[site.interactions.route]]
|
||||||
match = "/checkout/*"
|
match = "/checkout/*"
|
||||||
tier = "sessions"
|
tier = "transactional"
|
||||||
|
identity = "http-session"
|
||||||
|
payments = "server-invoice"
|
||||||
|
|
||||||
[[site.interactions.route]]
|
[[site.interactions.route]]
|
||||||
match = "/catalog/*"
|
match = "/catalog/*"
|
||||||
tier = "forms"
|
tier = "interactive-lite"
|
||||||
|
|
||||||
[site.protocols.tor]
|
[site.protocols.tor]
|
||||||
enabled = true
|
enabled = true
|
||||||
@@ -177,7 +185,7 @@ allow_javascript = false
|
|||||||
enabled = true
|
enabled = true
|
||||||
renderer = "gemtext"
|
renderer = "gemtext"
|
||||||
daemon_policy = "auto"
|
daemon_policy = "auto"
|
||||||
max_tier = "forms"
|
max_tier = "interactive-lite"
|
||||||
```
|
```
|
||||||
|
|
||||||
`max_tier` is a hard cap. If a route needs a higher tier than the protocol allows, AMPG
|
`max_tier` is a hard cap. If a route needs a higher tier than the protocol allows, AMPG
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ This file is generated from code. Do not edit it by hand.
|
|||||||
| site.outputs | `plan_root` | path | no | ../dist/ampg-plan | Generated plan artifact root. |
|
| site.outputs | `plan_root` | path | no | ../dist/ampg-plan | Generated plan artifact root. |
|
||||||
| site.interactions | `default_tier` | enum | no | static | Default interaction tier for routes. |
|
| site.interactions | `default_tier` | enum | no | static | Default interaction tier for routes. |
|
||||||
| site.interactions | `deny_routes` | array<string> | no | [] | Route patterns that must not be published. |
|
| site.interactions | `deny_routes` | array<string> | no | [] | Route patterns that must not be published. |
|
||||||
|
| site.interactions.route | `match` | glob | no | - | Route pattern for an explicit interaction policy. |
|
||||||
|
| site.interactions.route | `tier` | enum | no | site.interactions.default_tier | Interaction tier for a route group. |
|
||||||
|
| site.interactions.route | `identity` | enum | no | none | Identity adapter required by a route group. |
|
||||||
|
| site.interactions.route | `payments` | enum | no | none | Payment adapter required by a route group. |
|
||||||
| site.protocols.<name> | `enabled` | boolean | no | false | Whether this protocol target is built and planned. |
|
| site.protocols.<name> | `enabled` | boolean | no | false | Whether this protocol target is built and planned. |
|
||||||
| site.protocols.<name> | `renderer` | enum | no | <protocol> | Renderer profile to use for this protocol. |
|
| site.protocols.<name> | `renderer` | enum | no | <protocol> | Renderer profile to use for this protocol. |
|
||||||
| site.protocols.<name> | `daemon` | enum | no | protocol default | Ingress daemon adapter. |
|
| site.protocols.<name> | `daemon` | enum | no | protocol default | Ingress daemon adapter. |
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
# Generated Interaction Capabilities
|
||||||
|
|
||||||
|
> Status: generated | Updated by `python3 -m ampg docs generate` | Applies to: AMPG
|
||||||
|
|
||||||
|
This file is generated from code. Do not edit it by hand.
|
||||||
|
|
||||||
|
|
||||||
|
## Tiers
|
||||||
|
|
||||||
|
| Tier | Summary | Examples | Notes |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `static` | Rendered files only. | documentation, landing pages, catalog pages | Works across every currently modeled transport. |
|
||||||
|
| `interactive-lite` | Client-visible state with deterministic or server-rendered updates. | deterministic games, leaderboards, quote forms, status lookups | Does not require accounts or payment confirmation. Constrained transports may receive static snapshots or form-style actions. |
|
||||||
|
| `identity` | Authenticated sessions or signed wallet identity. | account pages, wallet sign-in, claim pages | Requires explicit identity adapter selection. HTTP transports can use strict cookies; wallet sign-in uses signed challenges. |
|
||||||
|
| `transactional` | Server-confirmed orders, wagers, deposits, invoices, or payment intents. | basic stores, paid downloads, game entry fees, donations | Requires explicit payment adapter selection. Callbacks, webhook receivers, and ledger internals remain internal. |
|
||||||
|
| `realtime` | Live multiplayer, dashboards, websocket streams, or fast state sync. | multiplayer games, live markets, operator consoles | HTTP transports only in the current model. Usually clearnet or private Tor/I2P until transport-specific realtime support exists. |
|
||||||
|
| `internal` | Private/admin/worker surfaces that must not be published automatically. | admin panels, webhooks, worker APIs, health endpoints | Always deny by default on public outputs. |
|
||||||
|
|
||||||
|
## Identity Adapters
|
||||||
|
|
||||||
|
| Adapter | Status | Transports | Notes |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `none` | `ready` | clearnet, tor, i2p, gemini, ipfs, reticulum | No account or signed identity required. |
|
||||||
|
| `http-session` | `planned` | clearnet, tor, i2p | Use HTTP-only cookies and strict transport-specific session scope. Profiles must not be shared across transports. |
|
||||||
|
| `siwe` | `planned` | clearnet, tor, i2p | Sign-In with Ethereum style challenge/response. Wallet transport availability is a browser-shell concern. |
|
||||||
|
| `signed-link` | `research` | gemini, reticulum | Use only for narrow flows with short-lived, scoped capabilities. |
|
||||||
|
|
||||||
|
## Payment Adapters
|
||||||
|
|
||||||
|
| Adapter | Status | Transports | Notes |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `none` | `ready` | clearnet, tor, i2p, gemini, ipfs, reticulum | No payment required. |
|
||||||
|
| `server-invoice` | `planned` | clearnet, tor, i2p | Server creates invoice or payment intent and confirms settlement. Callback/webhook routes stay internal. |
|
||||||
|
| `wallet-signature` | `planned` | clearnet, tor, i2p | Browser wallet signs a request; server verifies before fulfilling. |
|
||||||
|
| `static-instructions` | `planned` | gemini, ipfs, reticulum | Render payment instructions or donation addresses without automatic fulfillment. |
|
||||||
|
|
||||||
|
## Transport Limits
|
||||||
|
|
||||||
|
| Transport | Public Max Tier | Identity | Payments | Realtime | Notes |
|
||||||
|
| --- | --- | --- | --- | --- | --- |
|
||||||
|
| `clearnet` | `realtime` | http-session, siwe | server-invoice, wallet-signature | yes | Highest-fidelity browser surface. |
|
||||||
|
| `tor` | `transactional` | http-session, siwe | server-invoice, wallet-signature | private-only | Prefer server-rendered flows and reduced JavaScript by default. |
|
||||||
|
| `i2p` | `transactional` | http-session, siwe | server-invoice, wallet-signature | private-only | Prefer server-rendered flows and reduced JavaScript by default. |
|
||||||
|
| `gemini` | `interactive-lite` | signed-link research | static-instructions | no | Use curated prompts or polling-friendly status pages. |
|
||||||
|
| `ipfs` | `static` | none | static-instructions | no | Content-addressed snapshots; no server-confirmed state by default. |
|
||||||
|
| `reticulum` | `interactive-lite` | signed-link research | static-instructions | research | Resilient/private routing; not an anonymity layer. |
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# Interaction Capabilities
|
||||||
|
|
||||||
|
> Status: draft | Updated 2026-07-06 | Applies to: AMPG route exposure policy
|
||||||
|
|
||||||
|
Interaction capabilities define what AMPG may expose for dynamic applications. They are
|
||||||
|
public, generic rules. Project strategy, target names, and implementation notes belong in
|
||||||
|
`docs/private/`.
|
||||||
|
|
||||||
|
## Generated Policy
|
||||||
|
|
||||||
|
The code-owned policy tables live in
|
||||||
|
[generated interaction capabilities](generated/interaction-capabilities.md).
|
||||||
|
|
||||||
|
They cover:
|
||||||
|
|
||||||
|
- interaction tiers from `static` through `internal`.
|
||||||
|
- identity adapters such as HTTP sessions and wallet challenge/response.
|
||||||
|
- payment adapters such as server invoices and wallet-signed requests.
|
||||||
|
- per-transport limits for clearnet, Tor, I2P, Gemini, IPFS, and Reticulum.
|
||||||
|
|
||||||
|
## Rule
|
||||||
|
|
||||||
|
AMPG only exposes a route when the route tier, identity adapter, payment adapter, and
|
||||||
|
transport capability all agree. When in doubt, the route stays private.
|
||||||
+44
-78
@@ -1,39 +1,43 @@
|
|||||||
# Interactive Applications
|
# Interactive Applications
|
||||||
|
|
||||||
> Status: draft | Updated 2026-07-05 | Applies to: dynamic app support
|
> Status: draft | Updated 2026-07-06 | Applies to: dynamic app support
|
||||||
|
|
||||||
AMPG must support real applications without pretending every transport can offer the same
|
AMPG must support real applications without pretending every transport can offer the same
|
||||||
experience. The design goal is graceful capability mapping: expose the safest useful version
|
experience. The design goal is graceful capability mapping: expose the safest useful
|
||||||
of each surface on each protocol, and keep private surfaces private.
|
version of each public surface on each protocol, and keep private surfaces private.
|
||||||
|
|
||||||
## Interaction tiers
|
## Interaction Tiers
|
||||||
|
|
||||||
`static`
|
`static`
|
||||||
: Rendered files only. Works everywhere.
|
: Rendered files only. Works everywhere.
|
||||||
|
|
||||||
`forms`
|
`interactive-lite`
|
||||||
: Server-rendered GET/POST actions with full-page responses. Works on clearnet, Tor, I2P,
|
: Deterministic games, status lookups, quote forms, and other flows that do not require
|
||||||
and can be mapped to Gemini input prompts or Reticulum page scripts for simple actions.
|
account state or payment confirmation.
|
||||||
|
|
||||||
`sessions`
|
`identity`
|
||||||
: Authenticated account flows. Supported on HTTP transports with strict cookies. Gemini can
|
: Authenticated sessions, wallet sign-in, or signed capability links.
|
||||||
use client certificates or signed links later, but this is not a v1 requirement.
|
|
||||||
|
`transactional`
|
||||||
|
: Server-confirmed orders, wagers, deposits, invoices, donations, or payment intents.
|
||||||
|
|
||||||
`realtime`
|
`realtime`
|
||||||
: Rich browser UI, dashboards, live charts, websockets, or client-side state. HTTP transports
|
: Multiplayer, dashboards, websockets, streaming updates, or fast shared state.
|
||||||
only, and usually clearnet or private Tor/I2P.
|
|
||||||
|
|
||||||
`internal`
|
`internal`
|
||||||
: Worker APIs, webhooks, private admin APIs, payment callbacks, chain watchers, and service
|
: Admin, worker APIs, webhooks, callback endpoints, chain watchers, health checks, and
|
||||||
health endpoints. AMPG must not publish these automatically.
|
private operator surfaces. AMPG must not publish these automatically.
|
||||||
|
|
||||||
## Application adapter contract
|
The code-owned capability matrix lives in
|
||||||
|
[generated interaction capabilities](generated/interaction-capabilities.md).
|
||||||
|
|
||||||
|
## Application Adapter Contract
|
||||||
|
|
||||||
An application adapter describes what AMPG may expose:
|
An application adapter describes what AMPG may expose:
|
||||||
|
|
||||||
- upstream service and health check.
|
- upstream service and health check.
|
||||||
- OpenAPI spec or route manifest when available.
|
- OpenAPI spec or route manifest when available.
|
||||||
- route groups with interaction tier, auth requirement, and idempotency behavior.
|
- route groups with interaction tier, auth requirement, payment requirement, and idempotency behavior.
|
||||||
- form/action schemas for protocol translation.
|
- form/action schemas for protocol translation.
|
||||||
- public asset and cache policy.
|
- public asset and cache policy.
|
||||||
- private route denylist.
|
- private route denylist.
|
||||||
@@ -41,83 +45,45 @@ An application adapter describes what AMPG may expose:
|
|||||||
Adapters do not bypass the application. They translate constrained protocol input into the
|
Adapters do not bypass the application. They translate constrained protocol input into the
|
||||||
application's public action surface, then render safe responses.
|
application's public action surface, then render safe responses.
|
||||||
|
|
||||||
## Protocol mapping
|
## Protocol Mapping
|
||||||
|
|
||||||
| Tier | Clearnet | Tor/I2P | Gemini | Reticulum |
|
| Tier | Clearnet | Tor/I2P | Gemini | IPFS | Reticulum |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- |
|
||||||
| `static` | yes | yes | yes | yes |
|
| `static` | yes | yes | yes | yes | yes |
|
||||||
| `forms` | yes | yes, no JS by default | simple single-field prompts | simple scripts/actions |
|
| `interactive-lite` | yes | yes | curated prompts/status pages | static snapshots only | curated actions |
|
||||||
| `sessions` | yes | yes, strict cookies | later | later |
|
| `identity` | yes | yes, strict sessions | research | no | research |
|
||||||
| `realtime` | yes | optional private surface | no | no |
|
| `transactional` | yes | yes, explicit adapter | instructions/status only | instructions only | instructions/status only |
|
||||||
| `internal` | no public publish | no public publish | no | no |
|
| `realtime` | yes | private/opt-in only | no | no | research |
|
||||||
|
| `internal` | no public publish | no public publish | no | no | no |
|
||||||
|
|
||||||
## Challenge profile: Medusa multi-tenant platform
|
## Identity And Payments
|
||||||
|
|
||||||
Source: `../medusa-multi-tenant-platform`.
|
Identity and payments are optional adapters, not default site behavior. A route group must
|
||||||
|
explicitly request them before AMPG exposes account or payment flows on any transport.
|
||||||
|
|
||||||
Why it matters:
|
Supported design tracks:
|
||||||
|
|
||||||
- multi-tenant domain routing.
|
- strict HTTP sessions for clearnet, Tor, and I2P.
|
||||||
- storefront, tenant admin, backend, worker, database, Redis, S3/MinIO.
|
- Sign-In with Ethereum style challenge/response for HTTP transports.
|
||||||
- cart, checkout, orders, bookings, blogs, email, payment providers, and webhooks.
|
- server-created invoices or payment intents with internal callbacks.
|
||||||
- tenant-specific themes and custom domains.
|
- wallet-signed requests verified by the upstream app.
|
||||||
|
- static payment instructions for read-only or constrained outputs.
|
||||||
|
|
||||||
AMPG support target:
|
Payment callbacks, webhooks, ledger internals, worker routes, and private reconciliation
|
||||||
|
jobs remain `internal` even when public checkout or donation pages are exposed.
|
||||||
|
|
||||||
- Clearnet: adopt existing Caddy/reverse-proxy deployment.
|
## Design Constraints
|
||||||
- Tor/I2P: expose storefront routes with `forms` or `sessions` tier, no JavaScript by default.
|
|
||||||
- Gemini/Reticulum: expose catalog, blog, policy, product detail, and inquiry/request flows.
|
|
||||||
- Admin: `internal` unless explicitly bound to a private operator transport.
|
|
||||||
- Webhooks, payment callbacks, worker queues, health internals: always `internal`.
|
|
||||||
|
|
||||||
Required adapter capabilities:
|
|
||||||
|
|
||||||
- read tenant/domain registry or accept an exported tenant manifest.
|
|
||||||
- generate per-tenant protocol targets and daemon plans.
|
|
||||||
- cap checkout/payment routes by protocol.
|
|
||||||
- use OpenAPI route metadata where available.
|
|
||||||
- never expose tenant admin or backend admin by wildcard.
|
|
||||||
|
|
||||||
## Challenge profile: evaluetron / ai-gen-bot
|
|
||||||
|
|
||||||
Source: `../ai-gen-bot`.
|
|
||||||
|
|
||||||
Why it matters:
|
|
||||||
|
|
||||||
- OpenAPI-first core.
|
|
||||||
- customer storefront plus operator console.
|
|
||||||
- auth, payments, credit ledger, job queue, workers, moderation, and generated artifacts.
|
|
||||||
- public web channel, Telegram channel, internal worker APIs, and admin APIs.
|
|
||||||
|
|
||||||
AMPG support target:
|
|
||||||
|
|
||||||
- Clearnet: public storefront and docs.
|
|
||||||
- Tor/I2P: public storefront with server-rendered account/job flows when enabled.
|
|
||||||
- Gemini/Reticulum: catalog browsing, deposit instructions, simple generation request, and job
|
|
||||||
status lookup only after explicit adapter support.
|
|
||||||
- Operator console: private clearnet, LAN, mesh, or private onion only.
|
|
||||||
- Worker/internal routes: never published.
|
|
||||||
|
|
||||||
Required adapter capabilities:
|
|
||||||
|
|
||||||
- consume `api/openapi.yaml` as the action contract.
|
|
||||||
- map job creation to idempotent form submissions.
|
|
||||||
- render job status as polling-friendly pages.
|
|
||||||
- hide unavailable generators when no worker advertises the required capability.
|
|
||||||
- preserve the ledger and payment invariants of the upstream app.
|
|
||||||
|
|
||||||
## Design constraints learned from the challenge apps
|
|
||||||
|
|
||||||
- Public route discovery must start deny-first.
|
- Public route discovery must start deny-first.
|
||||||
- OpenAPI is useful, but not sufficient; route tiers and privacy intent must be explicit.
|
- OpenAPI is useful, but not sufficient; route tiers and privacy intent must be explicit.
|
||||||
- Admin and worker surfaces are separate sites or route groups, not accidental subpaths.
|
- Admin and worker surfaces are separate sites or route groups, not accidental subpaths.
|
||||||
- Gemini and Reticulum need curated actions, not automatic exposure of every POST route.
|
- Gemini, IPFS, and Reticulum need curated outputs, not automatic exposure of every POST route.
|
||||||
- Multi-tenant apps need generated protocol targets per tenant, with shared daemon adapters.
|
- Multi-tenant apps need generated protocol targets per tenant, with shared daemon adapters.
|
||||||
|
|
||||||
## Reusable checklist
|
## Reusable Checklist
|
||||||
|
|
||||||
- [ ] Classify every route group by interaction tier.
|
- [ ] Classify every route group by interaction tier.
|
||||||
- [ ] Deny private/admin/internal routes before enabling protocols.
|
- [ ] Deny private/admin/internal routes before enabling protocols.
|
||||||
- [ ] Prefer OpenAPI or route manifests over HTML scraping for actions.
|
- [ ] Prefer OpenAPI or route manifests over HTML scraping for actions.
|
||||||
- [ ] Provide safe alternates for constrained transports.
|
- [ ] Provide safe alternates for constrained transports.
|
||||||
- [ ] Verify no worker, webhook, payment callback, or admin route is publicly published.
|
- [ ] Verify no worker, webhook, payment callback, ledger internal, or admin route is publicly published.
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
PRIVATE_TARGET_TERMS = (
|
||||||
|
"wowrace",
|
||||||
|
"wowngeon",
|
||||||
|
"smirk-monorepo",
|
||||||
|
"medusa-multi-tenant-platform",
|
||||||
|
"ai-gen-bot",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class PublicPrivateSplitTest(unittest.TestCase):
|
||||||
|
def test_private_target_names_do_not_appear_in_public_docs(self):
|
||||||
|
failures = []
|
||||||
|
for path in sorted((ROOT / "docs").rglob("*.md")):
|
||||||
|
rel = path.relative_to(ROOT)
|
||||||
|
if "private" in rel.parts:
|
||||||
|
continue
|
||||||
|
text = path.read_text(encoding="utf-8").lower()
|
||||||
|
for term in PRIVATE_TARGET_TERMS:
|
||||||
|
if term in text:
|
||||||
|
failures.append(f"{rel}: contains private target term {term!r}")
|
||||||
|
self.assertEqual([], failures)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
Reference in New Issue
Block a user