NPS-Release

English 中文版

RFC Number: NPS-RFC-0003 Title: Three-tier Agent identity assurance levels for anti-scraping / trust gating Status: Accepted (Phase 1 — spec + .NET reference types landed) Author(s): Ori Lynn iamzerolin@gmail.com (LabAcacia) Shepherd: Ori Lynn (pre-1.0 fast-track per spec/cr/README.md) Created: 2026-04-21 Last-Updated: 2026-04-25 Accepted: 2026-04-25 (pre-1.0 fast-track; see spec/cr/README.md) Activated: (set when first reference SDK ships, target v1.0-alpha.3) Supersedes: none Superseded-By: none Affected Specs: NPS-3 NIP, NPS-2 NWP, spec/services/NPS-AaaS-Profile.md, spec/error-codes.md, spec/status-codes.md Affected SDKs: .NET, Python, TypeScript, Java, Rust, Go —

NPS-RFC-0003: Three-tier Agent identity assurance levels for anti-scraping / trust gating

1. Summary

Introduce three assurance levels for Agent identities — anonymous (L0), attested (L1), verified (L2) — and let Nodes declare a min_assurance_level in their NWM. The assurance level travels in IdentFrame and is carried as a critical X.509 extension (see NPS-RFC-0002 §4.1). This is NPS’s answer to “how do I know a request is from an Agent, not a scraper?” — the protocol doesn’t block scrapers, but it gives Nodes a primitive to demand verifiable Agent provenance and to charge / rate-limit / refuse accordingly.

2. Motivation

This RFC responds to a 2026-04-20 review comment:

最核心的,如果我要接这套协议,最关心的反而是怎么做反爬?我怎么 知道来个请求不是爬虫而是 Agent 访问?

(Most critically — if I adopt this protocol, my biggest concern is anti-scraping. How do I know a request is an Agent and not a scraper?)

The commenter is right that NPS today answers “who is this Agent?” (NIP) but not “how much do I trust this Agent’s identity?” An NID is just a public key — anyone, including a scraper farm, can mint one and sign requests with it. Without a way to rank identities by trustworthiness, Nodes either accept anonymous traffic (scraper-friendly) or hand-maintain allowlists (operational burden).

The X.509 PKI world solved the same class of problem with EV / OV / DV certificates and the CA/B Forum baseline. The identity-proofing world solved it with NIST SP 800-63 Identity Assurance Levels (IAL1/2/3). We adopt the tier shape, not the human-identity specifics.

The concrete business model this unlocks: an AaaS operator can price L2-verified Agent traffic higher than L0, auditors can require L2 for regulated integrations, and victims of scraper abuse can set min_assurance_level: attested on hot endpoints without breaking legitimate Agents that upgrade their NIDs.

3. Non-Goals

4. Detailed Design

4.1 Assurance Levels

Level Enum Minimum criteria Typical use
anonymous 0 Self-signed NID; no CA involvement; or CA-signed without identity binding Hobbyist Agents, dev/test, “show me a free quote” read-only endpoints
attested 1 NID signed by an RFC-0002-compliant CA; CA attests possession of the NID private key (ACME agent-01); contact email / domain verified by CA Most production Agents; rate-limit tier default
verified 2 L1 criteria plus CA attests the operator’s legal identity: corporate registration for org-NIDs, or signed attestation from a known AaaS operator for hosted Agents Regulated integrations (finance, healthcare), paid premium tiers, high-trust orchestration

What “attested” really buys a Node: the CA has verified that someone controls the NID private key and an out-of-band channel (ACME account email, domain, etc.), so if the Agent misbehaves the CA can at minimum email a human and at most revoke the cert. L0 offers neither.

What “verified” adds on top: the CA binds the NID to a legal entity. A Node can then issue an invoice, subpoena the operator, or make contract-grade claims about who it is interacting with.

4.2 Wire Format / Frame Changes

IdentFrame gains one field:

Field Type Required Description
assurance_level enum { anonymous, attested, verified } yes When the NID’s cert carries the id-nid-assurance-level extension (NPS-RFC-0002 §4.1), this field MUST carry the same value. Phase gate: Phase 1–2 (current) — verifiers SHOULD check and log mismatches, but enforcement is opt-in. Enforcement becomes MUST and triggers NIP-ASSURANCE-MISMATCH starting Phase 3 (flag day — see §8.1).

The cert is the source of truth; assurance_level in IdentFrame is redundant convenience for servers that don’t want to parse the cert just to route requests.

Phase 1–2 (current): Verifiers SHOULD check the cert extension and log any mismatch, but MAY skip enforcement. Implementations that do enforce MUST close the connection with NIP-ASSURANCE-MISMATCH.

Phase 3 (flag day, see §8.1): Verifiers MUST check the cert extension and MUST close the connection with NIP-ASSURANCE-MISMATCH if the two disagree. This is the hard deadline for completing the upgrade.

X.509 extension promotion (Phase 3 — not yet active): NPS-RFC-0002 defines id-nid-assurance-level (1.3.6.1.4.1.<PEN>.2.1) as non-critical. Starting Phase 3 flag day, this RFC promotes it to critical — old verifiers MUST reject certs that carry it as critical until they upgrade. That’s intentional: a Node that enforces min_assurance_level MUST NOT silently accept a verifier that can’t parse the extension. The promotion is NOT yet active in Phase 1–2.

4.3 Manifest / NWM Changes

NWM gains one optional top-level field:

# /.nwm excerpt
min_assurance_level: attested   # default: anonymous
auth:
  required_scopes: [...]
  min_assurance_level: verified  # per-action override (optional)

4.4 Error Codes

New entries in spec/error-codes.md:

Error Code NPS Status Description
NIP-ASSURANCE-MISMATCH NPS-CLIENT-BAD-FRAME IdentFrame.assurance_level disagrees with the cert extension
NWP-AUTH-ASSURANCE-TOO-LOW NPS-AUTH-FORBIDDEN Request’s assurance level < Node’s min_assurance_level
NIP-ASSURANCE-UNKNOWN NPS-CLIENT-BAD-FRAME Cert extension carries a value outside the defined enum

4.5 State Machines / Flows

Rejection path (Node enforces min_assurance_level: attested):

Agent (L0)                         Node
   │                                 │
   │── HelloFrame ─────────────────→ │
   │── IdentFrame (assurance=0) ───→ │
   │                                 │  check: 0 < 1 (attested)
   │ ←── ErrorFrame ──────────────── │  code: NWP-AUTH-ASSURANCE-TOO-LOW
   │     hint: "https://ca.../acme"  │  status: NPS-AUTH-FORBIDDEN
   │ ←── close                       │

Upgrade path is out-of-band: the Agent re-enrolls through an RFC-0002-compliant CA, receives a new cert with id-nid-assurance-level set to attested, and retries the connection.

4.6 Backward Compatibility


5. Alternatives Considered

5.1 Binary “verified or not” (two tiers)

Drop attested; only unverified and verified.

5.2 Reputation-only (skip levels)

Skip assurance levels; let Nodes rely on NPS-RFC-0004 reputation log instead.

5.3 Free-form CA policy OIDs

Let CAs define their own policy OIDs à la X.509 certificatePolicies; Nodes enumerate accepted OIDs in NWM.

5.4 Do nothing


6. Drawbacks & Risks


7. Security Considerations


8. Implementation Plan

8.1 Phasing

Phase Scope Exit criterion
1 .NET NIP parses cert extension; IdentFrame carries field; NWM parses min_assurance_level; enforcement optional Unit tests green; the default behavior is unchanged
2 All 6 SDKs + 6 CA servers; CA servers issue L1 certs via ACME; L2 issuance flow documented per CA Cross-SDK interop: L0/L1/L2 matrix green
3 min_assurance_level enforcement on by default when set in NWM; extension id-nid-assurance-level promoted to critical. Flag day: announced via NPS-Dev GitHub Discussions with ≥ 21 calendar days notice before the activation date; after activation, NIP-ASSURANCE-MISMATCH enforcement is MUST and non-compliant implementations MUST NOT claim any NPS conformance level No regressions; all 6 SDKs pass mismatch-enforcement tests
4 Remove L0-default fast path from Nodes that opted in to stricter defaults N/A — operators decide

8.2 SDK Coverage Matrix

SDK Owner Status Notes
.NET Ori Lynn pending Reference impl
Python TBD pending
TypeScript TBD pending
Java TBD pending
Rust TBD pending
Go TBD pending

8.3 Test Plan

  1. L0 Agent against min_assurance_level: attested Node → rejected with NWP-AUTH-ASSURANCE-TOO-LOW.
  2. L2 Agent against min_assurance_level: anonymous Node → accepted.
  3. Assurance mismatch (IdentFrame says L2, cert ext says L0) → NIP-ASSURANCE-MISMATCH.
  4. Per-action override: L1-globally, L2-on-orders.create → L1 Agent gets /invoke:orders.create rejected, other actions pass.
  5. Cert without extension against enforcing Node (post-Phase 3) → treated as L0 (implicit) and rejected if level > 0.
  6. Unknown enum value in cert → NIP-ASSURANCE-UNKNOWN.

8.4 Benchmarks


9. Empirical Data

None yet. Before Accepted, commit:

Metric Baseline Proposed Delta Method
NWM size no field +~40 B +~40 B JSON byte count
Per-request overhead not enforced ~1 µs +1 µs BenchmarkDotNet

10. Open Questions


11. Future Work


12. References


Appendix A. Revision History

Date Author Change
2026-04-21 Ori Lynn Initial draft
2026-04-25 Ori Lynn Accepted via pre-1.0 fast-track. Spec changes landed: NPS-3 §5.1.1 Assurance Levels + IdentFrame assurance_level field, NPS-2 NWM min_assurance_level field, error codes NIP-ASSURANCE-MISMATCH / NIP-ASSURANCE-UNKNOWN / NWP-AUTH-ASSURANCE-TOO-LOW. Phase 1 .NET reference types (NPS.NIP.AssuranceLevel enum, IdentFrame.AssuranceLevel, NipVerifyContext.MinAssuranceLevel, NeuralWebManifest.MinAssuranceLevel, related error/status code constants) landed alongside; active enforcement in the verifier remains opt-in per RFC §8.1 (Phase 1 = parse only, default unchanged). Phase 2 (other 5 SDKs + 6 CA Servers issuing L1 certs via ACME — depends on RFC-0002) deferred to v1.0-alpha.4. The X.509 critical-extension flip (§4.2) coordinates with RFC-0002 and is NOT yet active. AaaS-Profile §10 OQ-3 (Gateway enforcement vs backing-Node enforcement) deferred to CR-0001 follow-up.