Skip to content

feat(core): allow explicitly authored empty risk lists - #190

Merged
nishuzumi merged 2 commits into
nishuzumi:mainfrom
rainypilgrimage:codex/risk-empty-core
Sep 9, 2026
Merged

nishuzumi merged 2 commits into
nishuzumi:mainfrom
rainypilgrimage:codex/risk-empty-core

Conversation

@rainypilgrimage

Copy link
Copy Markdown
Contributor

What and why

Closes #164.

Core required every Capability to author risk, but Registry also rejected an explicit empty list. That forced adapters to publish a known-inaccurate label when the author had reviewed an operation and none of the current closed-set RiskLabels applied.

This change allows an explicitly authored risk: [] while keeping the field required. Missing or malformed metadata remains invalid, every non-empty member remains closed-set validated, and load() preserves the authored empty list unchanged.

The authoring guidance ships with the contract: contributors should raise a focused Core vocabulary issue when evidence identifies a missing reusable danger semantic, use [] only after review finds no applicable current category, and request maintainer review when uncertain. Receipt evidence remains authoritative and can refute the declaration.

Type of change

  • Protocol / Capability / Query
  • Core / simulator / MCP server
  • Bug fix
  • Documentation / example
  • Tooling / dependency

Framework and package impact

Registry now accepts an explicitly authored empty risk array while preserving required-field, array-shape, sparse-array, and unknown-label validation. The public RiskLabel[] shape does not change, and load() returns [] exactly as authored.

No new RiskLabel value is added, and no adapter, Simulator, MCP transport, or Monad Runtime behavior is changed. Downstream adoption remains with #158, #187, and the separately coordinated aPriori follow-up.

Verification

  • pnpm build
  • pnpm typecheck
  • pnpm lint
  • pnpm test
  • User-facing package changes include a changeset
  • Docs and examples match the implemented API

pnpm test currently reaches one unrelated Aave mainnet failure: PT_AUSD_8OCT2026 cleared the address-book age guard; vendor it and remove this quarantine. This branch does not modify Aave. The full offline-equivalent workspace run (MOSS_SKIP_E2E=1 pnpm test --reporter=dot) passes.

Protocol changes

N/A — this is a focused Core contract change and does not modify a Protocol adapter.

  • Parameters separate reusable Zod value types from field-purpose descriptions
  • Every Capability owns one direct TransactionNode and one typed Receipt
  • Receipt tests preserve every original Change object in exact length and order
  • Positive and @ts-expect-error fixtures cover exported type behavior
  • Fixed addresses and ABIs include sources and verification
  • A live Monad happy path returns zero Warnings

Evidence

  • Core: 8 test files and 73 tests pass.
  • Compile-time fixtures accept risk: [], reject a missing risk field, and preserve the closed RiskLabel set.
  • Runtime coverage accepts [] and rejects missing, non-array, sparse-array, and unknown-label metadata.
  • Registry load() projects the authored empty list unchanged.
  • Receipt coverage retains the original inbound and outbound nativeTransfer Changes, verifies that the inbound case has no account outflow, and demonstrates that outbound evidence refutes the no-outbound claim.
  • CONTEXT.md, MCP documentation, the protocol-onboarding guide and issue template, and an Agent-facing Core patch changeset carry the approved semantics and authoring rule.

@pillowtalk-Qy pillowtalk-Qy left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Box and @rainypilgrimage,

I independently reviewed a2d25655a0ee99a32d6f28780291257390f302df against main@19e602e and the scope accepted in #164. No blocking finding in this change.

The implementation distinguishes an explicit empty array from missing/non-array metadata; the per-member validation also rejects sparse entries and unknown labels. The public field remains required, the type fixtures retain the closed vocabulary, and Registry load() preserves []. The glossary, MCP documentation, onboarding guide/template and Core changeset consistently describe an authored classification, not a guarantee of safety.

The Receipt regression retains the original inbound/outbound Changes and demonstrates that contrary evidence refutes the declaration. It does not introduce a new runtime risk detector or change downstream adapters, which matches the agreed scope.

Independent verification on this exact head:

  • frozen install; lint; full workspace build and typecheck; git diff --check: pass;
  • pnpm test:offline: 685 passed / 42 skipped;
  • Core: 73/73; MCP: 22/22;
  • pnpm -r --no-bail test: completed, with 18 workspace commands passing and 2 failing. Aave is 35/36 due to the expired quarantine in #185; Kuru is 85/86 due to the native-swap ROUTE_QUOTE_UNAVAILABLE reported in #194. Both also reproduced on unchanged main. Pendle is 155/155.

This approval is for the reviewed Core change; it is not a claim that the full live gate is green or a replacement for maintainer merge/CI decisions. The existing Aave/Kuru failures remain separate follow-ups. No branch changes were made.

- ADR 0003 gains a dated section for the `risk: []` decision (nishuzumi#164):
  semantics, rejected alternatives (`fundIn`, sentinel, optional field),
  the authoring rule, and the Receipt-refutation requirement.
- AGENTS.md review rule: reject placeholder labels and `risk: []`
  without no-outbound Receipt coverage.
- Onboarding issue template: the rule becomes an HTML comment under the
  Risk labels column, matching every other guidance line.
- Changeset bumps `@themoss/core` as minor, consistent with prior
  `feat(core)` vocabulary changes; this is an Agent-facing contract change.
@nishuzumi

Copy link
Copy Markdown
Owner

@rainypilgrimage @pillowtalk-Qy — I audited exact head a2d25655 against main@19e602eb and the #164 decision. The Core change is correct and complete: Registry.use() accepts an authored risk: [], still rejects missing, non-array and unknown-label metadata, and now also rejects sparse arrays the old .some() check let through; load() projects [] unchanged and the MCP load shape is untouched. Compile-time fixtures are load-bearing in both directions, and all three constraints from #164 are met in substance.

Rather than another review round, I pushed one follow-up commit 0e9eb5b onto this branch (docs only, no code):

  • ADR 0003 gains a dated section "An authored empty risk list (2026-09-02)" recording the decision, the rejected alternatives (fundIn, a sentinel, an optional field), the authoring rule, and the Receipt-refutation requirement. The decision now lives with the rest of the closed-set taxonomy rather than only in the glossary.
  • AGENTS.md review rule: reject knowingly inaccurate placeholder labels, and reject risk: [] without Receipt test coverage asserting that no Change moves assets out of the account.
  • Issue template: the paragraph becomes an HTML comment under the "Risk labels" column, matching every other guidance line; as body text it would have been copied verbatim into every filed onboarding issue.
  • Changeset: @themoss/core bumped as minor, consistent with the prior feat(core) vocabulary changes (debt, perps); this is an Agent-facing contract change and belongs under "Minor Changes".

Independent verification on a2d25655: frozen install, lint, build, typecheck and the full offline suite pass (685 passed / 42 skipped; Core 73/73, MCP 22/22). Mutation checks confirm the new tests fail when the registry change is reverted, when for...of is swapped back to .some(), or when the Array.isArray guard is removed, and that the @ts-expect-error fixture fails both without the directive and with risk: [] supplied. Full live run with --no-bail: 18/20 workspace commands pass; Aave 35/36 (#185 expired quarantine, a wall-clock assertion) and Kuru 85/86 (#194) fail identically on unchanged main and are unrelated to this diff. The red ci check is that Aave failure stopping the recursive run early.

For the downstream owners: packages/protocols/apriori/README.md:78-80 and src/adapter.ts:190-192 still teach the superseded "Registry rejects an empty risk list" rule and must be fixed in the aPriori adoption follow-up. Adapters adopting [] should note that the fixture helper in this PR only inspects nativeTransfer; a no-outbound Receipt assertion for an ERC-20-paying claim (#187) must also cover event Transfer Changes.

Merging once the offline checks report on 0e9eb5b.

@nishuzumi
nishuzumi merged commit 93759e2 into nishuzumi:main Sep 9, 2026
1 of 2 checks passed
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.

[feature] Core: define how Capabilities declare that no current closed-set RiskLabel applies

3 participants