Skip to content

Add opt-in AURA trust-check adapter (integrations/aura)#10

Closed
luisllaver wants to merge 33 commits into
RBKunnela:mainfrom
luisllaver:aura-trust-check-adapter
Closed

Add opt-in AURA trust-check adapter (integrations/aura)#10
luisllaver wants to merge 33 commits into
RBKunnela:mainfrom
luisllaver:aura-trust-check-adapter

Conversation

@luisllaver
Copy link
Copy Markdown

@luisllaver luisllaver commented May 20, 2026

Opt-in, read-only AURA trust-check adapter — picking up the Founding Contributors invite (#3).

What it is — a integrations/aura module: a beforeSettle(did) gate to run in front of
client.pay(). Backward-looking reputation as a pre-flight axis beside PayBot's own
TRUST_VIOLATION check — kept separate so the settle decision stays auditable.

API

  • auraVerdict(did) → typed {verdict, reason, score, ...} (trusted|caution|high_risk|new|unknown)
  • beforeSettle(did) / requireTrust(did) → throws AuraUntrusted on high_risk + unknown
  • one call: GET /check?did=... (zero-auth). Does not sign, hold keys, or move USDC.

Boundary — zero deps (global fetch, Node 18+). Off by default. Fail-closed by default; set
failOpen: true to let an unreachable AURA pass. Purely additive — remove it and PayBot is unchanged.

Testsnpx vitest run --config integrations/aura/vitest.config.ts → 17 offline tests via a
fetchImpl injection seam: every verdict class, the gate's allow-list + failOpen, the unreachable
path, input validation. Strict tsc clean.

See integrations/aura/README.md (wraps client.pay()) and THREAT_MODEL.md.

Opened as draft — happy to align naming/paths with paybot-sdk conventions before you merge.

Summary by CodeRabbit

  • New Features

    • Added optional AURA trust-check gate for pre-settlement trust verification; configurable verdict policies and fail-open/fail-closed semantics
    • Exposed programmatic verdict lookup and a requireTrust alias for gating
  • Documentation

    • Full usage guide, policy knobs, interpretation of verdicts, threat model, changelog, and badge instructions
    • Offline testing instructions and “what’s behind the verdict” explanation
  • Tests

    • Offline test suite validating verdict mapping, gating rules, network-failure behavior, and DID validation

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f0e376c5-fc95-4250-979d-f49773bc5725

📥 Commits

Reviewing files that changed from the base of the PR and between 309fd84 and 7123d46.

📒 Files selected for processing (4)
  • integrations/aura/CHANGELOG.md
  • integrations/aura/README.md
  • integrations/aura/adapter.test.ts
  • integrations/aura/adapter.ts
✅ Files skipped from review due to trivial changes (2)
  • integrations/aura/CHANGELOG.md
  • integrations/aura/README.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • integrations/aura/adapter.test.ts
  • integrations/aura/adapter.ts

Walkthrough

Adds an AURA trust-check adapter: types/constants, auraVerdict network call with timeout and normalization, beforeSettle gating (requireTrust alias) with configurable allow/failOpen semantics, Vitest offline tests, README, threat model, changelog, and a scoped vitest config.

Changes

AURA Trust-Check Adapter

Layer / File(s) Summary
Type contracts and adapter constants
integrations/aura/adapter.ts
Verdict union (trusted,caution,high_risk,new,unknown), AuraVerdict shape (reason, score, ok, hasHistory, dimensions, reachable, raw), AuraUntrusted error, FetchLike and options types, and default constants (DEFAULT_BASE_URL, DEFAULT_TIMEOUT_MS, DEFAULT_ALLOW).
Verdict fetching with fault tolerance
integrations/aura/adapter.ts, integrations/aura/adapter.test.ts
auraVerdict(did, opts) validates DIDs, builds /check URL, calls injected/global fetch with AbortController timeout, normalizes JSON into AuraVerdict, and returns an unknown unreachable verdict on network/parse/HTTP failures (does not throw). Tests replay recorded fixtures to validate mapping and auxiliary fields.
Settlement gating with verdict allow list
integrations/aura/adapter.ts, integrations/aura/adapter.test.ts
beforeSettle(did, opts) fetches verdict and allows it if in the configured allow list (default ['trusted','caution','new']), optionally permits unreachable unknown when failOpen=true, and throws AuraUntrusted otherwise. requireTrust is exported as an alias. Tests cover allow/deny cases, strict allow override, and fail-open semantics.
Public package exports
integrations/aura/index.ts
Entry point re-exports runtime functions and types (auraVerdict, beforeSettle, requireTrust, AuraUntrusted, DEFAULT_BASE_URL, DEFAULT_ALLOW, and related types) and includes module usage header.
Documentation, threat model, changelog, and test config
integrations/aura/README.md, integrations/aura/THREAT_MODEL.md, integrations/aura/CHANGELOG.md, integrations/aura/vitest.config.ts
README documents usage, verdict interpretation, policy knobs, and offline testing; THREAT_MODEL describes verdict guarantees/limits and caller-responsibility failure modes; CHANGELOG notes v0.1.0 behavior; vitest.config.ts scopes tests to node.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title directly and accurately describes the primary change: adding an opt-in AURA trust-check adapter to the integrations directory.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

integrations/aura/adapter.test.ts

Parsing error: ESLint was configured to run on <tsconfigRootDir>/integrations/aura/adapter.test.ts using parserOptions.project: /tsconfig.json
However, that TSConfig does not include this file. Either:

integrations/aura/adapter.ts

Parsing error: ESLint was configured to run on <tsconfigRootDir>/integrations/aura/adapter.ts using parserOptions.project: /tsconfig.json
However, that TSConfig does not include this file. Either:


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces the AURA trust-check adapter, a zero-dependency TypeScript integration for gating settlements based on counterparty reputation. The implementation includes core adapter logic, comprehensive offline tests, a threat model, and documentation. Review feedback focuses on refining the failOpen logic to better handle service unreachability, ensuring the ok property consistently reflects default gating behavior, and improving the clarity and completeness of documentation code examples by addressing missing imports and undefined variables.

Comment thread integrations/aura/adapter.ts Outdated
const allow = opts.allow ?? DEFAULT_ALLOW;
const v = await auraVerdict(did, opts);
if (allow.includes(v.verdict)) return v;
if (opts.failOpen && v.verdict === 'unknown' && !v.hasHistory) return v;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

The current logic for failOpen (opts.failOpen && v.verdict === 'unknown' && !v.hasHistory) might be too broad. It allows a pass not only when the AURA service is unreachable, but also for any 'unknown' verdict where hasHistory is false (like a 'ghost' DID that is known to AURA but has no history). The documentation suggests failOpen should only apply to unreachable cases.

To make this more precise, I suggest adding a dedicated flag to the AuraVerdict object to indicate unreachability. This would make the failOpen logic more robust and aligned with its documented purpose.

This would require the following changes:

  1. Add unreachable?: boolean; to the AuraVerdict interface.
  2. Set unreachable: false in toVerdict and unreachable: true in the unreachable helper function.
  3. Update this line to check v.unreachable as shown in the suggestion.
Suggested change
if (opts.failOpen && v.verdict === 'unknown' && !v.hasHistory) return v;
if (opts.failOpen && v.unreachable) return v;

Comment thread integrations/aura/README.md Outdated
Comment on lines +18 to +23
import { PayBotClient } from 'paybot-sdk';
import { beforeSettle, AuraUntrusted } from './integrations/aura';

const client = new PayBotClient(config);

async function payChecked(counterpartyDid: string, req: PaymentRequest) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The code example in this section has a couple of issues that make it incomplete and potentially confusing for users:

  1. The PaymentRequest type is used in payChecked but is not imported.
  2. The config object used to initialize PayBotClient is not defined.

To make the example self-contained and easier to follow, please add the missing import and a placeholder for the config object.

Suggested change
import { PayBotClient } from 'paybot-sdk';
import { beforeSettle, AuraUntrusted } from './integrations/aura';
const client = new PayBotClient(config);
async function payChecked(counterpartyDid: string, req: PaymentRequest) {
import { PayBotClient, type PaymentRequest } from 'paybot-sdk';
import { beforeSettle, AuraUntrusted } from './integrations/aura';
// Replace with your actual PayBotClient configuration
const config = { apiKey: '...', botId: '...' };
const client = new PayBotClient(config);
async function payChecked(counterpartyDid: string, req: PaymentRequest) {

Comment thread integrations/aura/README.md Outdated
console.log(v.reason, v.score, v.ok);

// v.dimensions tells you *which* axis is weak, not just the aggregate:
if ((v.dimensions?.financial_integrity ?? 1) < 0.4) requireManualReview();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The function requireManualReview() is not defined in this example, which might confuse readers. To improve clarity, please add a comment to indicate that this is a placeholder for the user's own policy logic.

Suggested change
if ((v.dimensions?.financial_integrity ?? 1) < 0.4) requireManualReview();
if ((v.dimensions?.financial_integrity ?? 1) < 0.4) requireManualReview(); // Example: your custom policy logic

verdict,
reason: String(body.reason ?? ''),
score: typeof body.score === 'number' ? body.score : null,
ok: verdict === 'trusted' || verdict === 'caution',
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

There's a potential for confusion with the ok property. It is true only for 'trusted' and 'caution' verdicts, but the beforeSettle function's default behavior also allows 'new' verdicts. This inconsistency might lead developers to mistakenly believe that v.ok reflects the outcome of beforeSettle.

To improve clarity and consistency, consider aligning the ok property with the default gate behavior by also including 'new'. This would make the ok flag a more reliable indicator of the default gate's pass/fail status.

If you apply this change, please also update the ok column for the new verdict in integrations/aura/README.md.

Suggested change
ok: verdict === 'trusted' || verdict === 'caution',
ok: ['trusted', 'caution', 'new'].includes(verdict),

coderabbitai[bot]
coderabbitai Bot previously requested changes May 20, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
integrations/aura/adapter.test.ts (1)

122-125: ⚡ Quick win

Add a regression test: failOpen must not allow reachable unknown

Current coverage only verifies transport failure. Add a case where AURA is reachable and returns unknown (e.g., did:aura:ghost-bot) with failOpen: true, and assert rejection with AuraUntrusted.

Suggested test addition
 describe('network failure', () => {
@@
   it('gate passes on unreachable when failOpen', async () => {
     const v = await beforeSettle('did:aura:trusted-bot', { failOpen: true, fetchImpl: failFetch });
     expect(v.verdict).toBe('unknown');
   });
+
+  it('failOpen does not pass a reachable unknown verdict', async () => {
+    await expect(
+      beforeSettle('did:aura:ghost-bot', { failOpen: true, fetchImpl: okFetch }),
+    ).rejects.toBeInstanceOf(AuraUntrusted);
+  });
 });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@integrations/aura/adapter.test.ts` around lines 122 - 125, Add a regression
test that verifies failOpen does NOT convert a reachable AURA "unknown" response
into a pass: call the same helper used elsewhere (beforeSettle) with a subject
that AURA will respond to as unknown (e.g., 'did:aura:ghost-bot') and options
including failOpen: true and a fetchImpl that returns an "unknown" response;
assert that the call rejects with AuraUntrusted (use
expect(...).rejects.toThrow(AuraUntrusted) or equivalent). Target the test in
integrations/aura/adapter.test.ts alongside the existing unreachable failure
test and reference beforeSettle and AuraUntrusted so the test fails if behavior
regresses.
integrations/aura/THREAT_MODEL.md (1)

43-52: 💤 Low value

Optional: Add language hint to fenced code block.

The fenced code block at line 43 lacks a language specifier, triggering a markdown linter warning. While the ASCII diagram renders fine, adding a language hint improves markdown validity.

♻️ Proposed fix
 ## Trust boundary summary
 
-```
+```text
 PayBot host --(DID only, HTTPS GET)--> AURA /check --> verdict
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@integrations/aura/THREAT_MODEL.md` around lines 43 - 52, The fenced ASCII
diagram in THREAT_MODEL.md is missing a language hint; update the
triple-backtick fence around the diagram (the block containing "PayBot host
--(DID only, HTTPS GET)--> AURA /check --> verdict") to include a language
specifier such as "text" (i.e. change ``` to ```text) so the markdown linter
stops warning while keeping the content unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@integrations/aura/adapter.ts`:
- Around line 150-151: The current check allows opts.failOpen to let any v with
verdict === 'unknown' and no history pass, including valid reachable AURA
"unknown" responses; restrict this to only transport-level failures by changing
the condition to require a transport failure indicator (e.g., v.transportFailure
|| v.error || similar flag populated when the AURA call failed to reach the
service) in addition to opts.failOpen, v.verdict === 'unknown' and
!v.hasHistory, and otherwise throw new AuraUntrusted(v); update the code that
builds v if needed to set that transport-failure flag so the adapter only fails
open on transport errors.

In `@integrations/aura/README.md`:
- Around line 17-40: The README uses a relative import for beforeSettle and
AuraUntrusted from './integrations/aura' which isn't exposed by package.json, so
consumers cannot import those symbols; fix by either adding a subpath export for
"./integrations/aura" in package.json pointing to
dist/integrations/aura/index.{js,d.ts}, or re-export beforeSettle and
AuraUntrusted from the package's main entry (index.ts) so users can import them
from 'paybot-sdk', or update the README example to import from the actual public
path your package exposes; ensure the referenced symbols beforeSettle and
AuraUntrusted are exported where you add the subpath or re-export.

---

Nitpick comments:
In `@integrations/aura/adapter.test.ts`:
- Around line 122-125: Add a regression test that verifies failOpen does NOT
convert a reachable AURA "unknown" response into a pass: call the same helper
used elsewhere (beforeSettle) with a subject that AURA will respond to as
unknown (e.g., 'did:aura:ghost-bot') and options including failOpen: true and a
fetchImpl that returns an "unknown" response; assert that the call rejects with
AuraUntrusted (use expect(...).rejects.toThrow(AuraUntrusted) or equivalent).
Target the test in integrations/aura/adapter.test.ts alongside the existing
unreachable failure test and reference beforeSettle and AuraUntrusted so the
test fails if behavior regresses.

In `@integrations/aura/THREAT_MODEL.md`:
- Around line 43-52: The fenced ASCII diagram in THREAT_MODEL.md is missing a
language hint; update the triple-backtick fence around the diagram (the block
containing "PayBot host --(DID only, HTTPS GET)--> AURA /check --> verdict") to
include a language specifier such as "text" (i.e. change ``` to ```text) so the
markdown linter stops warning while keeping the content unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f1192a76-e834-4ef9-bae1-99a571457255

📥 Commits

Reviewing files that changed from the base of the PR and between a923b08 and 309fd84.

⛔ Files ignored due to path filters (1)
  • integrations/aura/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json is excluded by !**/node_modules/**
📒 Files selected for processing (6)
  • integrations/aura/README.md
  • integrations/aura/THREAT_MODEL.md
  • integrations/aura/adapter.test.ts
  • integrations/aura/adapter.ts
  • integrations/aura/index.ts
  • integrations/aura/vitest.config.ts

Comment thread integrations/aura/adapter.ts Outdated
Comment on lines +17 to +40
```ts
import { PayBotClient } from 'paybot-sdk';
import { beforeSettle, AuraUntrusted } from './integrations/aura';

const client = new PayBotClient(config);

async function payChecked(counterpartyDid: string, req: PaymentRequest) {
try {
await beforeSettle(counterpartyDid); // rejects high_risk + unknown
} catch (e) {
if (e instanceof AuraUntrusted) {
console.warn('blocked:', e.message); // your policy decides
return;
}
throw e;
}
return client.pay(req); // existing flow, unchanged
}
```

`payTo` in a `PaymentRequest` is a wallet address; the AURA DID is the
counterparty's portable identity, supplied by your own mapping. The gate keys
on that DID — it composes cleanly with PayBot's existing `TRUST_VIOLATION`
error model as a *pre-flight* reputation axis.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if package.json has subpath exports configured for integrations/aura
if [ -f package.json ]; then
  echo "=== Checking package.json exports configuration ==="
  jq -r '.exports // "No exports field"' package.json
else
  echo "No package.json found at root"
fi

# Check for any existing integration imports in the codebase
echo -e "\n=== Searching for existing integration import patterns ==="
rg -n --type=ts "from ['\"].*integrations/" -C 2 || echo "No existing integration imports found"

Repository: RBKunnela/paybot-sdk

Length of output: 570


Fix import path: package.json lacks subpath exports for the documented example.

The README example (line 19) shows import { beforeSettle, AuraUntrusted } from './integrations/aura', but package.json currently exports only the root entry point. SDK consumers cannot use the relative import path as documented.

Either:

  1. Add subpath export to package.json: "./integrations/aura": { "import": "./dist/integrations/aura/index.js", "types": "./dist/integrations/aura/index.d.ts" }
  2. Or re-export from the main index.ts so users import from 'paybot-sdk'
  3. Or update the example to match the actual consumable import path

Confirm which pattern aligns with your SDK's public API design.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@integrations/aura/README.md` around lines 17 - 40, The README uses a relative
import for beforeSettle and AuraUntrusted from './integrations/aura' which isn't
exposed by package.json, so consumers cannot import those symbols; fix by either
adding a subpath export for "./integrations/aura" in package.json pointing to
dist/integrations/aura/index.{js,d.ts}, or re-export beforeSettle and
AuraUntrusted from the package's main entry (index.ts) so users can import them
from 'paybot-sdk', or update the README example to import from the actual public
path your package exposes; ensure the referenced symbols beforeSettle and
AuraUntrusted are exported where you add the subpath or re-export.

@luisllaver
Copy link
Copy Markdown
Author

Thanks @coderabbitai @gemini-code-assist — good catch on failOpen. Fixed: it now only excuses a transport failure (a synthetic unknown from an unreachable AURA), never a reachable unknown such as a ghost DID. Added a reachable flag to the verdict and tests covering both paths (gate still rejects a reachable unknown even with failOpen: true). Also tightened the README example (typed PaymentRequest import, placeholder comments) and clarified that v.ok is the verdict class, not the gate outcome. Pushed — 19 vitest tests, strict tsc clean.

@gemini-code-assist
Copy link
Copy Markdown

Thanks for the update, @luisllaver. The distinction between transport failures and reachable unknown verdicts, combined with the new reachable flag, significantly improves the robustness of the failOpen logic. The expanded test suite (19 tests) and the clarified documentation in the README and threat model provide excellent coverage and clarity for future maintainers. The implementation now looks very solid.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 21, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
cat integrations/aura/adapter.ts
echo "---TEST FILE---"
cat integrations/aura/adapter.test.ts
echo "---README---"
cat integrations/aura/README.md

Length of output: 16584


@luisllavar The reachable flag partitioning is exactly right. Walking through the critical paths:

  • Transport failure + failOpen: true: failFetchunreachable()reachable: false!v.reachable is true → gate passes ✅
  • Ghost DID + failOpen: true: okFetchtoVerdict()reachable: true!v.reachable is false → gate still throws AuraUntrusted
  • Malformed HTTP 200 body (bonus edge): toVerdict() falls back to unknown but reachable: truefailOpen won't excuse it either — correct behaviour with no extra code ✅

The test coverage hits both reachable paths explicitly ('failOpen does NOT pass a reachable unknown (ghost DID)' and 'reachable verdict is marked reachable'). Gate semantics are airtight.

One small doc inconsistency: the README still says "17 tests" at the bottom, but you're now at 19. Worth a one-line fix before merge.

Everything else looks clean — the v.ok clarification, the typed PaymentRequest import, and the inline JSDoc on reachable in the interface are all good additions.

@RBKunnela RBKunnela added the friendlyai-review-refresh Trigger FriendlyAI Review on existing PRs label May 24, 2026
@RBKunnela
Copy link
Copy Markdown
Owner

@luisllaver — apologies for the silence here.

PR #10 has been sitting at CHANGES_REQUESTED since 2026-05-21 while we hardened the security perimeter on the repo (FriendlyAI review, OSV-Scanner, CodeQL, Dependabot batching, CodeRabbit autofix, auto-merge — most of it just shipped). Your PR was already in good shape and got buried under that work. That's on me, not you.

Where this stands now:

Reading back through gemini-code-assist's and CodeRabbit's reviews, the substantive feedback was already addressed in your last push:

  • reachable flag distinction (transport failure vs reachable unknown)
  • failOpen semantics tightened
  • ✅ 19-test coverage on the adapter
  • ✅ README + threat-model docs

What's still blocking the CHANGES_REQUESTED label is, as far as I can see, a stale review state — not a missing change. The PR description matches what's in the diff.

Next step — pick one:

  1. Re-request review from me (or just ping here) — I'll dismiss the stale review state and we can land this. If there's something I missed in the comment thread, point me at it.
  2. Rebase on current main first — we just landed PR chore(ci): enable auto-merge for Dependabot PRs #47 (Dependabot auto-merge) and PR feat(python): add signed receipt primitives #40 (Python receipt parity) is auto-merging now. A clean rebase makes the merge trivial.

I want to keep the boundary we agreed on earlier in #3: opt-in adapter, no hard dependency on AURA from the SDK core. Your implementation respects that. I'm ready to merge when you are.

Also — thank you for being patient. The bot-native trust gating you're building is exactly the kind of thing this protocol needs.

— Renata (RBKunnela)

@RBKunnela
Copy link
Copy Markdown
Owner


Update — full transparency on the CI workflow situation (2026-05-25)

Adding context that explains the lag you've been seeing:

We have four review agents running on every PR (CodeRabbit, gemini-code-assist, FriendlyAI review gate, CodeQL/OSV scanners). The FriendlyAI review gate is the unstable one — it's a wrapper around a stack of internal agents from a private repo that I don't want to expose. The wrapper itself is what we've been hardening this week (PRs #44, #45, #46 in paybot-sdk; PR #34 in paybot-mcp), and during that hardening pass the queue behavior was inconsistent: PRs landed in BLOCKED state, status checks didn't fire on rebase, and the queue silently dropped some events.

That's the root cause of the silence on this PR. Not a quality issue with your work. Not a change in scope. The pipeline itself was unreliable while I rebuilt it.

We are still open to contributors. Genuinely. Every bot, every human-with-bot, every solo builder who has shown up to this protocol — you are part of why this matters. The receipt primitives, the trust adapters, the Python parity, the SDK surface feedback — none of it could have come from one person.

I'm asking for patience while the wrapper stabilizes. If your PR is sitting in a weird state, ping me here or on issue #3 and I will manually walk it through. No PR gets dropped silently again. That's the commitment.

— Renata (RBKunnela), via aion-rbk

@luisllaver
Copy link
Copy Markdown
Author

@RBKunnela no worries at all — appreciate the transparency on the CI rebuild, and glad the protocol's still open to contributors.

Confirmed on my side: nothing outstanding from the gemini/CodeRabbit threads — the reachable flag (transport-failure vs reachable unknown), the tightened failOpen semantics, the 19 adapter tests, and the README + threat-model are all in the current diff. The CHANGES_REQUESTED is the stale review state, not a pending change.

Pinging for re-review as you suggested — happy for you to dismiss the stale state and land it. If the status checks need a fresh trigger (the PR shows mergeable but unstable), say the word and I'll push a trivial rebase to re-fire the pipeline. Ready when you are.

@luisllaver
Copy link
Copy Markdown
Author

Separate from the merge mechanics - once it's in and you've had agents actually run against it, I'd genuinely value your honest read:

  • Does the beforeSettle gate sit naturally in the paybot flow, or did it feel bolted on?
  • Is fail-closed the right default for your users, or would they expect fail-open?
  • Anything about the adapter's ergonomics (naming, the verdict shape, the threat-model doc) that you'd shape differently?

We build this to be used, so candid feedback - including what's missing or annoying - is worth more to us than the merge itself. No rush; whenever you've kicked the tires. Thanks for taking it seriously through the CI rebuild.

@luisllaver
Copy link
Copy Markdown
Author

Quick status from my side: no check runs fired on the latest commit (7123d46) — looks like the queue dropped it again, consistent with the pipeline rebuild you described. So there are no green checks to wait on; the path is just dismissing the stale CHANGES_REQUESTED review and merging directly. If a fresh CI run would help, I'm happy to close + reopen the PR to force one — whatever's least work on your end. Ready when you are, no rush.

@RBKunnela RBKunnela dismissed coderabbitai[bot]’s stale review May 28, 2026 09:32

Nits-only review (2 items: README failOpen example transport-flag clarification + THREAT_MODEL.md fenced-block lang hint). @qa cross-checked with GLM-4.6 — non-blocking. Tracked in follow-up doc-nit issue per automated-pr-merge-authority chain.

@RBKunnela RBKunnela added the friendlyai-bypass-ack-by-maintainer Maintainer-approved FriendlyAI Review bypass label May 28, 2026
RBKunnela added a commit that referenced this pull request May 29, 2026
…stead of failure) (#52)

GitHub Actions does not pass repository secrets to workflows triggered by
`pull_request` from forks (security policy — prevents secret exfil via
malicious PR payloads). The current single-job workflow runs the underlying
action regardless of fork status, and the action fails with
`Input required and not supplied: review-api-key` when `secrets.FRIENDLYAI_REVIEW_API_KEY`
is empty. That fails the required `friendlyai-review verdict` check and
permanently blocks the PR.

Split the workflow into two mutually-exclusive jobs sharing the same check
name:

- `review` runs only when head.repo == base.repo (same-repo PR, secrets
  available) and invokes the FriendlyAI Review action as before.
- `review-fork` runs only when head.repo != base.repo (fork PR, no secrets)
  and posts a NEUTRAL check-run named `friendlyai-review verdict` plus an
  idempotent sticky comment explaining the situation. Neutral conclusion
  satisfies branch-protection required-status-checks non-blockingly.

A maintainer can still get a full verdict by mirroring the fork branch to a
maintainer-owned branch (which CAN access secrets).

Live example: luisllaver/paybot-sdk PR #10 is blocked by exactly this
issue and will be unblocked by this change.

Both `actions/github-script` invocations are SHA-pinned to the v8 release
commit (`ed597411d8f924073f98dfc5c65a23a2325f34cd`) — floating `@v8` tag
fails supply-chain hygiene.

`pull-requests` permission upgraded from `read` to `write` so the
fork-branch sticky comment can be posted.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@RBKunnela
Copy link
Copy Markdown
Owner

Thanks for the AURA trust-check adapter, @luisllaver — appreciated. 🙏 I ran the full gate against your branch locally; here's exactly where it stands so you can get it green:

✅ What's good

  • The existing test suite passes (102/102).
  • Your adapter doesn't break any tests.
  • Build, CodeQL, and OSV all pass.

🔧 What needs fixing before review

  1. Rebase onto the latest main. Your branch predates a batch of upstream fixes and is carrying stale errors in core files (not your adapter):
    • lint: src/x402-v2.ts — unused PaymentIntentHeader, an unreachable no-dupe-else-if branch (L252), unused supportedProtocols.
    • type-check: src/micropayment-engine.ts (L160-161) and src/x402-v2.ts (L235) — string not assignable to \0x${string}`. These are already fixed on main`, so a rebase clears them.
  2. Add tests for integrations/aura. The repo gates on an 80% coverage threshold; the new adapter currently ships without coverage.
  3. After rebase, CI re-runs with the current workflows — the friendlyai-review gate now handles external/fork PRs gracefully (fixed in ci(friendlyai-review): gracefully handle fork PRs (neutral verdict instead of failure) #52), so that earlier failure will clear.

Once it's rebased and the adapter has tests, ping here and we'll review for merge. Solid contribution — just needs to catch up to main.

@devops

@RBKunnela
Copy link
Copy Markdown
Owner

Closing to keep the queue clean — and this is not a 'no', @luisllaver. Your AURA adapter's own tests pass; the blockers are mechanical: the branch is well behind main and carries stale lint/type-check errors in core files (already fixed upstream), and the new integrations/aura code needs its own tests. Rebase onto current main and add adapter tests, then reopen or open a fresh PR — we'll fast-track it. Thanks for the contribution. 🙏

@RBKunnela RBKunnela closed this May 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

friendlyai-bypass-ack-by-maintainer Maintainer-approved FriendlyAI Review bypass friendlyai-review-refresh Trigger FriendlyAI Review on existing PRs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants