Skip to content

rfc: ADR-0007 trust-tier policy DSL + ADR-0008 cartridge marketplace (epic #87 items 4 + 10)#92

Merged
hyperpolymath merged 1 commit into
mainfrom
rfc/0007-0008-trust-tier-marketplace
May 20, 2026
Merged

rfc: ADR-0007 trust-tier policy DSL + ADR-0008 cartridge marketplace (epic #87 items 4 + 10)#92
hyperpolymath merged 1 commit into
mainfrom
rfc/0007-0008-trust-tier-marketplace

Conversation

@hyperpolymath
Copy link
Copy Markdown
Owner

Summary

Two coupled RFCs for epic #87 Tier B. Coupled because they share trust-tier vocabulary — ADR-0008's submission protocol requires every cartridge to ship a default policy bundle in the schema ADR-0007 defines.

No code in this PR. Pure design docs. Implementation tracked separately in epic #87 (items 4 and 10).

ADR-0007 — Trust-tier policy DSL

Adopt Nickel as the policy DSL (extends the existing `coord-messages.ncl` investment), with a clean PEP/PDP split:

  • PEP stays in `mcp-bridge/main.js` (where the existing `hardeningGate` lives)
  • PDP is a new `policy-mcp` cartridge that the bridge consults per `tools/call`

Schema: per-cartridge × per-tool × `{tier, rate_limit, required_role, master_approval, allowed_args, side_effect}`. Verdicts: `allow` / `deny` / `rate_limit` / `require_approval` (the last routes through `coord_send_gated`-style quarantine).

Default policy bundle covers all 41 bridge tools out of the box. Migration sequence covered explicitly in the ADR's "Open questions" section.

ADR-0008 — Cartridge marketplace

Activates the Ayo tier, which currently has exactly one member and no protocol. New repo `hyperpolymath/cartridge-index` holds signed entries (ML-DSA-87 per EXHIBIT-B) pointing to source repos at content-pinned revs.

Promotion path: outside → Ayo → Shield → Teranga. Promotion is recorded in the index, not the source repo, so cartridges don't need to "know" their tier.

Critically: respects ADR-0002 (BoJ-only MCP). Community capabilities flow into BoJ as cartridges, never as standalone MCPs.

Default-safe posture: Ayo cartridges are visible via `boj_marketplace_search` but never auto-loaded; user must explicitly `boj_marketplace_install --accept-ayo-tier`.

Why this pair, this order

The epic specifies they ship together: "Items 4 + 10 RFCs together (they share the trust-tier vocabulary)." 0007 defines what a policy bundle looks like; 0008 requires every submission to ship one. Either alone leaves a hole.

Review focus

The ADRs are formatted for substantive engagement, not rubber-stamp. Each has explicit:

  • Consequences (positive + negative) — not just "this is good"
  • Non-goals — what we deliberately won't do
  • Open questions — decisions explicitly deferred to implementation

Recommend reading the Open questions sections — that's where the load-bearing choices that need your call live.

What this doesn't change

  • No code touched.
  • No existing cartridges affected.
  • ADR-0002 stands; this RFC pair operates strictly within its constraints.

Sequencing

Per epic #87: this is Tier B step 1 of 3. Next pair (items 2 + 3: sandbox cartridge + cross-machine federation) follows in a sibling PR; the third pair (items 5 + 6: webhooks + sampling) after that. All three pairs are independent of each other and of the code PRs (#88/#89/#91).

🤖 Generated with Claude Code

…arketplace

Two coupled RFCs for epic #87 Tier B (items 4 + 10). Coupled because
they share trust-tier vocabulary — the marketplace submission protocol
in 0008 requires each cartridge to ship a default policy bundle in the
schema defined by 0007.

ADR-0007 — Trust-tier policy DSL
- Adopt Nickel as the policy DSL (extends existing coord-messages.ncl
  investment)
- PEP/PDP split: PEP stays in mcp-bridge/main.js; PDP is a new
  policy-mcp cartridge consulted per tools/call
- Schema: per-cartridge × per-tool × {tier, rate_limit, required_role,
  master_approval, allowed_args, side_effect}
- Verdicts: allow / deny / rate_limit / require_approval (with
  master-approval quarantine integration)
- Default bundle covers all 41 bridge tools; ships at repo root
- BOJ_POLICY_MODE = enforce | audit | off; BOJ_POLICY_FAIL_MODE for
  cold-start posture
- Aligns with NIST RBAC 4.0 reference architecture so future migration
  to OPA/Rego (if needed) is mechanical

ADR-0008 — Cartridge marketplace
- Activates the Ayo tier (currently inactive)
- New hyperpolymath/cartridge-index repo holds signed entries pointing
  to source repos at content-pinned revs
- Submission protocol: PR against cartridge-index/inbox/ with signed
  entry + ML-DSA-87 signature + manifest_sha256 + abi_sha256 + policy
- CI verifies hashes, signatures, policy schema, license, file structure
- Promotion path: outside → Ayo → Shield (security-reviewed) → Teranga
  (formally verified); recorded in index, not source repo
- New bridge tools: boj_marketplace_search, boj_marketplace_install
- New MCP resources: boj://marketplace/index, boj://marketplace/cartridges/<name>
- Default-safe: Ayo cartridges never auto-loaded; explicit user opt-in
- Reuses estate's quantum-safe-provenance (ML-DSA-87) signature standard

Both RFCs include consequences (positive + negative), explicit non-goals,
and open questions calling out decisions deferred until implementation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 29 issues detected

Severity Count
🔴 Critical 18
🟠 High 4
🟡 Medium 7

⚠️ Action Required: Critical security issues found!

View findings
[
  {
    "reason": "Stale AI session file -- delete",
    "type": "stale",
    "file": "GEMINI.md",
    "action": "delete",
    "rule_module": "root_hygiene",
    "severity": "medium"
  },
  {
    "reason": "Issue in quality.yml",
    "type": "missing_workflow",
    "file": "quality.yml",
    "action": "create",
    "rule_module": "workflow_audit",
    "severity": "high"
  },
  {
    "reason": "Issue in security-policy.yml",
    "type": "missing_workflow",
    "file": "security-policy.yml",
    "action": "create",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Action hyperpolymath/standards/.github/workflows/governance-reusable.yml@main needs attention",
    "type": "unpinned_action",
    "file": "governance.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "high"
  },
  {
    "reason": "Python file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/boj-server/boj-server/.github/scripts/validate-eclexiaiser.py",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/boj-server/boj-server/cartridges/sanctify-mcp/adapter/mod.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/boj-server/boj-server/cartridges/academic-workflow-mcp/adapter/mod.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/boj-server/boj-server/cartridges/fireflag-mcp/adapter/mod.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/boj-server/boj-server/cartridges/ephapax-mcp/adapter/mod.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/boj-server/boj-server/cartridges/bofig-mcp/adapter/mod.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  }
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

@hyperpolymath hyperpolymath merged commit 2f8cd93 into main May 20, 2026
16 of 19 checks passed
@hyperpolymath hyperpolymath deleted the rfc/0007-0008-trust-tier-marketplace branch May 20, 2026 06:38
hyperpolymath added a commit that referenced this pull request May 20, 2026
…epic #87 items 5 + 6) (#95)

## Summary

Third and final RFC pair for epic #87 Tier B. Both ADRs concern
**server-initiated MCP messages** — webhooks fan out
\`notifications/event\` to clients; sampling sends
\`sampling/createMessage\` to clients. Both are opt-in per client and
require graceful fallback when the client doesn't cooperate.

**No code in this PR.** Pure design docs.

## ADR-0011 — Webhooks inbound + MCP notifications

Closes the agent feedback loop: external events surface as MCP
\`notifications/event\` instead of forcing agents to poll.

- **Six providers v1**: github, gitlab, cloudflare, sentry, stripe,
generic
- **Single listener**: \`POST /webhooks/{provider}/{token}\` on the
existing Cowboy endpoint (ADR-0004 preserved)
- **Per-provider signature verification** — HMAC-SHA256, JWS as
appropriate; signature-rejected events never reach the notification path
- **Subscription persistence** at \`~/.boj/webhooks/\` (chmod 0600);
managed via 5 new bridge tools
(\`boj_webhook_subscribe/list/unsubscribe/rotate/replay\`)
- **Bounded replay buffer** (100 events × N subscriptions) so
reconnecting clients catch up
- **Fan-out by selector** — broadcast, by \`client_kind\`, or by
\`peer_token\`

## ADR-0012 — Server-initiated sampling

\`sampling/createMessage\` is MCP's underused reverse path. BoJ uses it
for **two specific patterns**, both opt-in per call site:

| Pattern | When |
|---|---|
| Composition router | \`boj_cartridge_invoke\` against an ambiguous
intent (e.g. "deploy and monitor") — ask the LLM which cartridge fits |
| Clarification | An argument could match multiple backends — ask the
LLM (which knows the user) which one |

**Budget-bounded**: \`BOJ_SAMPLING_BUDGET_PER_SESSION\` (default 50);
exceeded → deterministic fallback. **Always has fallback**: client
rejection or timeout never blocks.

**Hard NO list**: never in security-critical paths, never to ask "should
I proceed?", never for input validation.

Per-call OTel span (depends on PR #91) so sampling activity is
observable in the user's existing telemetry.

## Why this pair

Both are **server-initiated**, both are **opt-in per client**, both
**degrade gracefully**. Coupling them in one review surfaces the shared
protocol concerns (client cooperation, fallback discipline, audit
attribution) in one place.

## Review focus

Recommend reading **Open questions** in both:

- ADR-0011: subscription persistence across restarts; backpressure on
slow clients; provider extensibility (config vs code); authorization
tier for subscription creation
- ADR-0012: system-prompt safety; sampling-decision caching;
multi-client target heuristic; cost attribution; fallback determinism

## What this doesn't change

- No code touched.
- No existing tools or cartridges affected.
- ADR-0004 (single listener) preserved by 0011; ADR-0007 (policy DSL)
extended by both (sampling result feeds a policy-gated tool call;
webhook subscriptions are policy-gated artefacts).

## Sequencing

This completes epic #87 Tier B (all 6 RFCs across PRs #92, #93, this
one). Tier A is complete in code (#89, #91). Tier C is the long-running
proof campaigns — separate work, no RFCs needed at this stage.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
hyperpolymath added a commit that referenced this pull request May 20, 2026
## Summary

`.github/scripts/validate-eclexiaiser.py` was the residual baseline-rot
that surfaced after #114 (ReScript exemption) removed the fail-fast —
the `governance / Language / package anti-pattern policy` step then
reached its Python sub-check and flagged it. This was the blocker on
#115.

Per the canonical Hyperpolymath Language Policy, Python is wholly
outlawed estate-wide with zero exemptions (only carve-out is SaltStack
`_states`/`_modules`/`pillar`, which this file isn't). Replace with a
POSIX-shell + awk validator doing the same three checks:

1. `[project]` section has a non-empty `name`
2. At least one `[[functions]]` table is declared
3. Each function table has a non-empty `name` and `source`

The new script has no TOML-parser dependency.

## Test plan

- [x] Local: happy path on current eclexiaiser.toml -> Valid: boj-server
(1 function(s)) exit 0
- [x] Local: 3 failure modes each return exit 1 with the correct error
message
- [ ] CI: Validate eclexiaiser manifest step (Dogfood Gate) continues to
pass
- [ ] CI: governance / Language / package anti-pattern policy step now
passes

Refs hyperpolymath/standards#67 (Estate Language Policy).
Refs hyperpolymath/standards#89 (was blocking the #92 allowlist work).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant