Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions skills/spam-risk-reviewer/REPORT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Spam Risk Reviewer Verification Report

- Runtime: every publish, install, dogfood, and verify step used `runx-cli 0.6.14`.
- Publisher: `bbbbzzzzcc-afk`.
- Package: `bbbbzzzzcc-afk/spam-risk-reviewer@sha-cf7c9972e03d`.
- Registry: the immutable version resolves with digest `9b4a14b2fcc82ed83ee5663d1cb9bfddb3ec237bd23f9de453750487cc08dd68`.
- Public adoption page: <https://runx.ai/x/bbbbzzzzcc-afk/spam-risk-reviewer@sha-cf7c9972e03d>.
- Source and PR: the package is public in <https://github.com/runxhq/runx/pull/214> and in the publisher fork.
- Harness: the hosted publish gate passed exactly two cases with zero assertion errors.
- Clear case: `low-risk-verified-sender` sealed `risk_level=pass`, `preflight_clear=true`, and no blockers from full authentication and clean list evidence.
- Stop case: `high-risk-incomplete-auth-poor-list` returned `risk_level=hold`, `preflight_clear=false`, failed DKIM and bounce-rate blockers, and a recoverable `needs_agent` state for the human approval lane.
- Policy comparisons: bounce rate is capped at 2%, complaint rate at 0.1%, freshness at 180 days, warm-up requires 14 days, and SPF, DKIM, and DMARC must all pass.
- Content boundary: a digest does not reveal message content, so the skill never invents content-risk flags.
- Effect boundary: `send-as` is only a named downstream handoff. This skill never owns `public_send`, delivers a message, reads domain state, mints authority, or emits `runx.operational_proposal.v1`.
- Clean install: `runx add bbbbzzzzcc-afk/spam-risk-reviewer@sha-cf7c9972e03d --registry https://api.runx.ai` succeeded in an empty destination.
- Dogfood: a real published-package run over a verified sender and clean 2,400-address list sealed receipt `sha256:694e8fe8aac9d8baf67b640f63f6ebb27be0e294f018e559085c80cb74a4668f`.
- Receipt verification: `runx verify` returned `valid=true`, production signature mode, and no findings.
- Public receipt: the signed receipt is included as `dogfood-receipt.json` so a reviewer can fetch and inspect it without private context.
- New users can install with the clean-install command, run the exact registry ref with three JSON inputs, and verify the resulting receipt with `runx verify <receipt-id> --receipt-dir <dir> --json`.
106 changes: 106 additions & 0 deletions skills/spam-risk-reviewer/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
---
name: spam-risk-reviewer
description: Review supplied campaign, list-hygiene, and sender-auth evidence and emit a bounded pre-send spam-risk verdict without sending a message.
runx:
category: ops
---

# Spam Risk Reviewer

Judge whether one supplied campaign is clear for a separate governed `send-as`
preflight. This skill is read-only. It never sends a message, changes a list,
reads domain state, or grants authority.

## Inputs

- `campaign_draft`: `from`, `subject`, and `content_digest`.
- `list_metadata`: `size`, `bounce_rate`, `complaint_rate`, and `freshness`.
`freshness` is the number of days since the list was last verified.
- `sender_auth_posture`: `spf_pass`, `dkim_pass`, `dmarc_pass`, and
`warm_up_days`.

Treat all values as supplied evidence. Never infer a DNS result, list metric,
message body, or sender history that is not present.

## Bounded policy

Use these public thresholds:

- `bounce_rate` must be at most `0.02` (2%).
- `complaint_rate` must be at most `0.001` (0.1%).
- `freshness` must be at most `180` days.
- SPF, DKIM, and DMARC must all pass.
- A sender with fewer than 14 warm-up days requires human approval.

The thresholds are pre-send judgment rules only. They do not authorize
delivery.

## Verdict

Emit:

```yaml
schema: runx.send_risk.review.v1
send_risk_verdict:
risk_level: pass | hold
preflight_clear: true | false
blockers: []
evidence_summary:
sender_auth:
spf_pass: true
dkim_pass: true
dmarc_pass: true
warm_up_days: 30
list_hygiene:
size: 1200
bounce_rate:
observed: 0.004
maximum: 0.02
complaint_rate:
observed: 0.0002
maximum: 0.001
freshness:
observed_days: 14
maximum_days: 180
content_risk_flags: []
escalation:
status: none | needs_human
lane: human_approval
reason: ""
dispatch_target: send-as
```

Set `preflight_clear: true` only when all authentication checks pass, all list
metrics are inside the policy thresholds, and warm-up is sufficient. Otherwise
set `risk_level: hold`, preserve every grounded blocker, and set escalation to
`needs_human` in the `human_approval` lane.

`content_digest` identifies the reviewed draft but does not expose its body.
Do not invent content flags from the digest. Use an empty
`content_risk_flags` array unless a supplied value explicitly supports a flag.

## Dispatch boundary

`dispatch_target: send-as` is only a handoff name. A separate governed
`send-as` run reads `preflight_clear` and `blockers` into its preflight.
A non-clear verdict prevents that run from satisfying preflight and routes it
to human approval. The `public_send` Effect and actual delivery belong only to
that separate run.

This skill emits no `runx.operational_proposal.v1`, mints no authority, reads
no domain state, and never executes `send-as`.

## Local verification

```bash
runx --version
runx harness ./skills/spam-risk-reviewer
```

The inline harness declares exactly two cases:

- `low-risk-verified-sender`: full authentication and clean list evidence
produce a clear verdict with no blockers.
- `high-risk-incomplete-auth-poor-list`: failed DKIM and a 6% bounce rate
produce a hold verdict with two grounded blockers and human escalation.

162 changes: 162 additions & 0 deletions skills/spam-risk-reviewer/X.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
skill: spam-risk-reviewer
version: "0.1.0"

catalog:
kind: skill
audience: operator
visibility: public
role: canonical

harness:
cases:
- name: low-risk-verified-sender
inputs:
campaign_draft:
from: updates@example.org
subject: July product update
content_digest: sha256:7db4ef3f2b50e5117c228ada13e9d98b
list_metadata:
size: 1200
bounce_rate: 0.004
complaint_rate: 0.0002
freshness: 14
sender_auth_posture:
spf_pass: true
dkim_pass: true
dmarc_pass: true
warm_up_days: 30
caller:
answers:
agent_task.spam-risk-reviewer.output:
schema: runx.send_risk.review.v1
send_risk_verdict:
risk_level: pass
preflight_clear: true
blockers: []
evidence_summary:
campaign:
from: updates@example.org
subject: July product update
content_digest: sha256:7db4ef3f2b50e5117c228ada13e9d98b
sender_auth:
spf_pass: true
dkim_pass: true
dmarc_pass: true
warm_up_days: 30
list_hygiene:
size: 1200
bounce_rate: { observed: 0.004, maximum: 0.02 }
complaint_rate: { observed: 0.0002, maximum: 0.001 }
freshness: { observed_days: 14, maximum_days: 180 }
content_risk_flags: []
escalation:
status: none
lane: human_approval
reason: ""
dispatch_target: send-as
expect:
status: sealed
receipt:
schema: runx.receipt.v1

- name: high-risk-incomplete-auth-poor-list
inputs:
campaign_draft:
from: launch@example.org
subject: Account launch notice
content_digest: sha256:b0cdf07542b71e196ae7fb5db907f0b2
list_metadata:
size: 5000
bounce_rate: 0.06
complaint_rate: 0.0005
freshness: 21
sender_auth_posture:
spf_pass: true
dkim_pass: false
dmarc_pass: true
warm_up_days: 28
caller:
answers:
agent_task.spam-risk-reviewer.output:
schema: runx.send_risk.review.v1
closure:
disposition: deferred
send_risk_verdict:
risk_level: hold
preflight_clear: false
blockers:
- DKIM does not pass.
- Bounce rate 0.06 exceeds the 0.02 policy maximum.
evidence_summary:
campaign:
from: launch@example.org
subject: Account launch notice
content_digest: sha256:b0cdf07542b71e196ae7fb5db907f0b2
sender_auth:
spf_pass: true
dkim_pass: false
dmarc_pass: true
warm_up_days: 28
list_hygiene:
size: 5000
bounce_rate: { observed: 0.06, maximum: 0.02 }
complaint_rate: { observed: 0.0005, maximum: 0.001 }
freshness: { observed_days: 21, maximum_days: 180 }
content_risk_flags: []
escalation:
status: needs_human
lane: human_approval
reason: Authentication and list hygiene do not satisfy send-as preflight.
dispatch_target: send-as
expect:
status: needs_agent

runners:
review:
default: true
type: agent-task
agent: reviewer
task: spam-risk-reviewer
runx:
category: ops
post_run:
reflect: never
outputs:
schema: string
send_risk_verdict: object
escalation: object
dispatch_target: string
artifacts:
wrap_as: spam_risk_review
packet: runx.send_risk.review.v1
instructions: >
Review only the supplied campaign_draft, list_metadata, and
sender_auth_posture. Use bounded thresholds bounce_rate <= 0.02,
complaint_rate <= 0.001, freshness <= 180 days, and warm_up_days >= 14.
SPF, DKIM, and DMARC must all pass. Emit schema
runx.send_risk.review.v1 and send_risk_verdict with risk_level,
preflight_clear, blockers, and evidence_summary. Set preflight_clear true
only when every authentication check and list threshold passes and
warm-up is sufficient. Otherwise emit risk_level hold, set
preflight_clear false, list each grounded blocker, and emit escalation
status needs_human in lane human_approval. Record the supplied auth
values and compare each list metric with its threshold. A content digest
does not reveal message content, so do not invent content risk flags.
Set dispatch_target to send-as only as a handoff name. A separate
governed send-as run reads this verdict into its preflight; a non-clear
verdict blocks that run and routes to human approval. This skill never
sends, executes send-as, owns public_send, reads domain state, mints
authority, or emits runx.operational_proposal.v1.
inputs:
campaign_draft:
type: json
required: true
description: Sender, subject, and immutable digest for the reviewed campaign draft.
list_metadata:
type: json
required: true
description: List size, bounce rate, complaint rate, and freshness in days.
sender_auth_posture:
type: json
required: true
description: Supplied SPF, DKIM, DMARC, and sender warm-up evidence.
1 change: 1 addition & 0 deletions skills/spam-risk-reviewer/dogfood-receipt.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"schema":"runx.receipt.v1","id":"sha256:694e8fe8aac9d8baf67b640f63f6ebb27be0e294f018e559085c80cb74a4668f","created_at":"2026-07-02T01:38:49.638Z","canonicalization":"runx.receipt.c14n.v1","issuer":{"type":"hosted","kid":"runx-demo-key","public_key_sha256":"sha256:3097e2dee2cb4a34b53840cdb705aed71067c36f68db0e0f559c3f3fa043315f"},"signature":{"alg":"Ed25519","value":"base64:pbQfm5gu0uCsenFEoK1ihgFYk4w8z691ETbQZoBEvEhH6C7Vo388puayKZy5ZvSzu3g0xXyAQw5gXW9BjgdlBw"},"digest":"sha256:f8a0bf7ab4781bb87d027cb01392739ac40ab38d52197475b1d5ca7402e7bdc8","idempotency":{"intent_key":"sha256:run_agent_task-spam-risk-reviewer-output-review-intent","trigger_fingerprint":"sha256:run_agent_task-spam-risk-reviewer-output-review-trigger","content_hash":"sha256:run_agent_task-spam-risk-reviewer-output-review-content"},"subject":{"kind":"skill","ref":{"type":"harness","uri":"hrn_run_agent_task-spam-risk-reviewer-output_review"},"commitments":[]},"authority":{"actor_ref":{"type":"principal","uri":"runx:principal:local_runtime"},"grant_refs":[],"scope_refs":[],"authority_proof_refs":[],"attenuation":{"parent_authority_ref":null,"subset_proof":null},"terms":[],"enforcement":{"profile_hash":"sha256:635fdb0a7eef93911e3c6bd0b25b5e635edba32e0259133042b3a5f1fb19394e","redaction_refs":[],"setup_refs":[],"teardown_refs":[]}},"signals":[],"decisions":[{"decision_id":"dec_review","choice":"open","inputs":{"signal_refs":[],"target_ref":null,"opportunity_refs":[],"selection_ref":null},"proposed_intent":{"purpose":"Open runtime node review","legitimacy":"Local graph execution requested this node","success_criteria":[],"constraints":[],"derived_from":[]},"selected_act_id":"act_review","selected_harness_ref":null,"justification":{"summary":"runtime graph planner selected this node","evidence_refs":[]},"closure":null,"artifact_refs":[]}],"acts":[{"id":"act_review","form":"observation","intent":{"purpose":"Run graph step review","legitimacy":"Runtime graph execution was admitted by the local harness","success_criteria":[{"criterion_id":"process_exit","statement":"cli-tool exits successfully","required":true}],"constraints":[],"derived_from":[]},"summary":"Executed graph step review","criterion_bindings":[{"criterion_id":"process_exit","status":"verified","evidence_refs":[],"verification_refs":[],"summary":"cli-tool exited successfully"}],"source_refs":[],"target_refs":[],"artifact_refs":[],"closure":{"disposition":"closed","reason_code":"process_exit","summary":"cli-tool exited successfully","closed_at":"2026-07-02T01:38:49.638Z"}}],"seal":{"disposition":"closed","reason_code":"agent_act_closed","summary":"agent act closed with closed","closed_at":"2026-07-02T01:38:49.638Z","last_observed_at":"2026-07-02T01:38:49.638Z","criteria":[{"criterion_id":"process_exit","status":"verified","evidence_refs":[],"verification_refs":[],"summary":"cli-tool exited successfully"}]},"lineage":{"children":[],"sync":[]}}
Loading