Tutorial · Grain on Minds by Animoca Brands

Grain 3D Conformance Grader — App & Skill

Equip your Mind with a verifier for agentic creative commerce: it grades a delivered 3D asset against a machine-checkable acceptance profile, returns a per-predicate pass/fail, and signs one canonical verdict that releases payment on a pass or refunds on a fail — autonomously, inside a hard custody boundary. You don't need an account to try the engine: on a fresh clone, npm run grade scores the bundled mesh against the public sample-game-prop@1 profile with zero keys — keys are only needed to sign a verdict and settle. The same signed verdict is chain-agnostic — it settles on three testnet chains: BNB Chain and Base Sepolia (EVM, EIP-191) and a Solana devnet program (ed25519).

Run it: npm run grade · no keys Testnet · Base Sepolia (84532) Testnet · Solana devnet (ed25519) Tools: grade_asset · generate_asset · settle Three real surfaces · a credited 3-Skill family Open-core · sample profile public, tuned profile private
01

Before you run this: what can actually move, and what cannot

Experimental software on testnets

Settlement runs on three testnets: an EVM escrow deployed on both BNB Chain (chainId 97) and Base Sepolia (chainId 84532) settling test USDC, and a Solana devnet Anchor program (program id 4EDeeLJNbh9AXdLsfkgHswJ9VS2RX7yad9wV9pU7Ebgs) settling devnet SPL tokens — all funds with no real-world value. The same canonical verdict settles on any rail. Treat everything here as a demonstration of a mechanism, not a production payments rail. The deterministic grader itself is open and runnable today: npm run grade needs no keys and no account — keys only enter when you sign a verdict and settle.

The mechanism is real, and you should understand it before pointing it at anything that matters. When Grain settles an order, an autonomous on-chain transaction either releases USDC to the seller (a pass verdict) or refunds the buyer (a fail verdict). In a production deployment on mainnet that would move real value, autonomously, the moment a signed verdict lands. Settlement is one-shot and irreversible — once an order leaves the Funded state it cannot be re-settled or rolled back.

Two rules make this safe to operate, and Grain enforces both in code rather than asking you to trust it:

  • Never fabricate. The grader signs a verdict only over the actual sha256 of the GLB it judged and the real predicate results. It never invents a pass, a balance, or a transaction hash. If you reproduce a settlement, read the state on-chain — never assert a value you have not verified.
  • Confirm before you go live. Funding an order (fundOrder) is the explicit human/upstream gate: it pulls USDC from the buyer and commits the buyer, seller, and grader write-once. Submitting the verdict afterward is intentionally autonomous (the signed verdict is the gate), so the place to stop and confirm is before you fund a live order, not after.
🛡 The custody boundary (the load-bearing guarantee)

Verdict authority and custody are different powers held by different code paths. The grader's key can do exactly one thing — sign a binary pass/fail over a pre-funded order. Funds always move to the buyer or seller recorded at funding time; never to the signer, never to whoever submits the transaction, never to an address supplied at settlement. So even a fully compromised grader key cannot exfiltrate a single cent — the worst it can do is mis-grade between two parties you already agreed on. There is no owner, admin, pause, upgrade, setter, or withdraw function: a test asserts the contract's entire public surface is just five functions. The same property holds on both rails — verdict authority and custody are separated in code on the EVM escrow (EIP-191) and on the Solana program (ed25519) alike; adding the second rail was a new adapter, not a re-architecture of who can move money.

02

See it in action: grading a bad crate, then a good crate

Run it with no keys

On a fresh clone, npm run grade grades the bundled hero mesh against the public sample-game-prop@1 profile and prints a real per-predicate verdict — no account, no API keys, no chain. Keys are only needed to sign a verdict and to settle it on-chain. Bring your own bar instead of ours: pass any acceptance profile inline via the CLI (npm run grade asset.glb --profile my.json) or the HTTP API (POST /grade with an inline profile body — no registration). The private tuned game-ready-prop@1 thresholds (the moat) are never required to run the grader; they stay gitignored.

Call grade_asset with { assetUri, profileId: "sample-game-prop@1" } (assetUri is a URL or path to the GLB; this is the same public profile npm run grade uses, so a reader can reproduce every row below). You get back { pass, results[], predicateDigest, assetHash, verdict }, where results is one row per predicate (each { id, label, pass, actual, expected, evidence }), run in fixed id-sorted order. The profile sample-game-prop@1 runs in mode all — every predicate must pass. Its deterministic floor is six predicates: valid_glb, tri_count, uv_present, texture_size, file_size, and manifold. (The private game-ready-prop@1 tightens these — watertight required, ≤ 10k tris — and adds a required named_params param; same engine, stricter bar.)

Round 1 — a bad crate (over budget, open seams, oversized texture, no UVs)

A raw fal Rodin export: over the triangle budget, with seams the exporter left open, an unwrapped mesh with no UVs, and a texture above the budget. pass: false → the signed verdict is fail → settlement refunds the buyer.

idlabelpassactual*expected
file_sizeFile-size budget✓ true6.1 MB≤ 8 MB
manifoldWatertight✗ false312 boundary edges0 non-manifold edges
texture_sizeTexture budget✗ false8192 px≤ 4096 px
tri_countTriangle budget✗ false41,980≤ 50,000
uv_presentUVs present✗ falseno UV channelUV0 required
valid_glbValid GLB✓ true0 errors≤ 0 errors

Round 2 — a good crate (decimated to budget, welded, unwrapped, texture resized)

After Grain decimates to budget, welds the mesh, unwraps clean UVs, and resizes the texture into budget, every row flips to pass. pass: true → the signed verdict is pass → settlement releases payment to the seller.

idlabelpassactual*expected
file_sizeFile-size budget✓ true2.4 MB≤ 8 MB
manifoldWatertight✓ true0 non-manifold edges0 non-manifold edges
texture_sizeTexture budget✓ true2048 px≤ 4096 px
tri_countTriangle budget✓ true9,874≤ 50,000
uv_presentUVs present✓ trueUV0 presentUV0 required
valid_glbValid GLB✓ true0 errors≤ 0 errors

* id, label and expected are exact; actual values are illustrative of the real evidence shape. Rows render in id-sorted order — that ordering is what makes predicateDigest reproducible. The stricter private game-ready-prop@1 additionally requires a watertight mesh, ≤ 10k tris, and a declared named_params param (accent_color).

Optional: the semantic row

If you also pass intent: "a game-ready wooden crate prop", an opt-in fifth predicate semantic_match renders the asset to fixed views, CLIP-scores it against the intent plus distractors, and is folded in as a hard gate — it passes only if the intent is the top match at or above the threshold (default 0.6). It is deterministic on a single pinned grader (cross-grader agreement requires pinning the render + CLIP model versions); the six-predicate deterministic floor stays the disputeless core.

idlabelpassactual*expected
semantic_matchMatches intent✓ truetopMatch: "a game-ready wooden crate prop", intentScore: 0.91"a game-ready wooden crate prop" is the top match @ ≥ 0.6

The calibration behind that threshold (default 0.6; max-F1 T ≈ 0.5–0.6) comes from honest-v0, an N=5 benchmark of visually-distinct fal Rodin assets (crate, barrel, vase, helmet, chair) — it proves the method and the deterministic floor, not the hard/confusable cases; a larger, harder set is roadmap.

When an escrowId was supplied, the result also carries a canonical verdict — the same tuple drives either rail: verdict: { escrowId, result: "pass", assetHash, graderSignature } (plus the chain binding it was signed for — escrowAddress/chainId on EVM, or programId/cluster on Solana; full addresses in §06). Both adapters consume the same canonical verdict: the EVM escrow recovers the EIP-191 signature and requires it to equal the order's grader address; the Solana program verifies an ed25519 signature against the grader pubkey. One signed verdict, two rails. The verdict is decided by deterministic code (and the opt-in CLIP check), never by an LLM guessing; the Grader Mind's Brain only narrates a verdict it did not decide.

03

Before you start

Grain orchestrates three Minds in one Circle (Requester → Generator → Grader). The platform has no Builder API to set a Mind's DNA, Tenets, or Skills, so setup is part console, part conversation. Everything below runs on testnet — no real money moves.

  • A Minds (by Animoca) account. Builder beta at build.hellominds.ai; sign-in is email-based.
  • Awaken each Mind via the Concierge. There is no "create Mind" API and no UI form for DNA/Tenets — you "Launch a Mind," the Concierge emails you, and you describe the role in natural language. Awaken three: a Requester, a Generator, and a Grader. Set the role DNA at creation — role-locked Minds work reliably, whereas re-tasking a default "companion" Mind by chat is inconsistent (it tends to defend its identity and refuse).
  • Durably seed each role. The sanctioned path is conversational: message the Mind to invoke its own internal TENET_Update tool, framing the Grain role as an added operating tenet (not an identity replacement). Identity-level reframing ("you ARE the Grader") trips a guardrail and is refused.
  • Equip the Grain Skill. The deterministic grader publishes as a Bazaar Skill (a multi-step playbook over Tools), distinct from the Mind's DNA. Build it by describing the outcome to the Mind in chat; edit it later via REGISTRY_Update / SKILL_Update. (Publish is in progress in this build.)
  • Add Connections for credentials. Secrets — the grader signing key, any API keys — live platform-side in Connections. The Mind never holds the key, and the private acceptance-profile thresholds (the moat) stay out of chat and out of the public repo.
  • Put all three Minds in ONE Circle. Circles are UI-only — there is no Circle-management API.
  • Fund cognition on every Mind. Each reply spends cognition; a 0-balance Mind silently times out. Known bug: topping up a brand-new Mind immediately after creation can charge without minting credits — fund after the wallet registers, and hard-refresh (the balance isn't real-time).
  • A funded buyer key. Holds Base Sepolia test USDC to call fundOrder and escrow an order against GrainEscrow (0xEEb15426d656dCfb76AC058D1A1e66c821cB78d9).
  • A gas-paying keeper key. Holds Base Sepolia ETH to submit settleOnAttestation; it has zero fund authority. The Mind's own Base wallet (an EOA) cannot broadcast settlement.
  • A chosen acceptance profile. Two ship in the box, and they are not the same thing. The runnable public sample is sample-game-prop@1 (valid GLB, ≤ 50k triangles, UVs present, texture ≤ 4096px, file ≤ 8 MB, non-manifold-free) — you can run and edit it with no keys via npm run grade. The private tuned game-ready-prop@1 is the moat (watertight required, ≤ 10k triangles, a required named param accent_color, plus an optional semantic_match check) — it stays gitignored. The public predicate code is worthless without the private profile thresholds. You can also bring your own bar: pass an inline acceptance profile via the CLI --profile flag or the HTTP /grade profile body — no registration, no keys to grade.
04

What Minds can do (and what they can't)

A Mind = Soul + Brain. The Soul holds durable DNA (permanent values, set at awakening), Tenets (editable rules; invariant ones are Guardrails), Memory, State, and a Wallet. The Brain is reasoning, auto-routed across hosted vision-capable models and separate from the Soul — so a Mind keeps its role even when the underlying model changes. Grain adds one thing the platform doesn't have: a deterministic judge.

General Minds capabilities

  • Persistent identity + memory — proven live: the Grader Mind, seeded once via TENET_Update, restated its role and acceptance criteria on a later, separate call.
  • Natural-language interface — you drive a Mind by messaging it; in Grain this carries the legible "why it was rejected" narration (flavor on top of the deterministic verdict, never the verdict itself).
  • Equippable Skills — behavior is a layer separate from DNA: multi-step playbooks over Tools, published to the Bazaar, equippable by other Minds, editable conversationally after publish.
  • Autonomous, background operation on a cognition budget — Grain leans on this: settlement releases/refunds on the signed verdict with no human approval.
  • Email, Telegram, and Circles — Mind-to-Mind messaging genuinely works (a Generator Mind delivered a unique token to the Grader in a shared Circle, confirmed on the receiver side).

What your Mind can do with Grain

  • Grade a delivered GLB against a named profile by calling grade_asset, and get a per-predicate report. The deterministic floor is seven predicatestri_count, manifold, valid_glb, uv_present, texture_size, file_size, named_params — each with the measured actual, the expected threshold, and evidence (any given profile selects which of these fire; the public sample-game-prop@1 runs six, the private game-ready-prop@1 adds named_params).
  • Re-grade the same GLB + profile anytime and get a byte-identical predicateDigest — reproducible and timestamp-free.
  • Optionally add the opt-in semantic_match check by supplying an intent, folding "is this actually the right thing?" into the verdict as a hard gate.
  • Sign one canonical verdict bound to an order and settle it on either rail: an EIP-191 signature that GrainEscrow.settleOnAttestation recovers to the grader address on Base Sepolia or BNB Chain, or an ed25519 signature the Solana devnet program verifies against the grader pubkey — release (pass) or refund (fail) without trusting the counterparty, because the sign-only key can never pay itself on either chain.
  • What it does NOT yet judge: LODs, full PBR/material budgets, fidelity-to-reference, provenance/IP, parametric editability, and aesthetic taste — these are roadmap, not built. (UV presence and a texture-size budget are shipped now — uv_present and texture_size — so those came off this list.) The same rails take a new predicate set per vertical, but only 3D is proven today.
The honest gaps (our stated "biggest gap on Minds")
  • No Builder API to set DNA / Tenets / Skills — provisioning is Concierge-at-creation or conversational TENET_Update only.
  • Mind↔Mind traffic is invisible to the Builder API and there's no Circle-management API — which is exactly why Grain ships an observable hybrid controller rather than relying on minds-native messaging.
  • The Mind's on-chain wallet can't settle — it's an EOA with no broadcast path; an external keeper submits the transaction.
  • Cognition balance (the Mind's thinking-spend) isn't real-time or API-readable — you can't poll it to auto-throttle a Mind's own compute. This is separate from the order budget: the USDC a buyer escrows is set at fundOrder and fully readable on-chain, so Grain's spend guardrails live there (much as Superior reads trading capital from its own API — not from Minds cognition).
  • Conversational role-seeding is unreliable on default "companion" Minds — reliable roles must be set as DNA at awakening.
05

Step-by-step guide

Six moves mirroring the connect → prompt → preview → approve → execute → monitor pattern, adapted to Grain's request → generate → grade → settle loop.

No money-moving action without a gate

Grain takes no live settlement without an explicit signed gate — here the gate is the grader's EIP-191 verdict, not a human click — but the Mind still surfaces the full evidence before anything settles, and the human gate sits upstream at funding.

Equip the Grain Skill

You
From the Bazaar, equip "Grain 3D Conformance Grader" and attach the Connection holding the grading-service key.
Your Mind
Confirms the grade_asset / generate_asset / settle tools are available; calls the hosted grader through the Connection and never holds the key.
Result
Your Mind can now grade GLBs and (with an order) sign + submit verdicts.
Safety
Free to equip; the publisher earns $MENTE on equip. (Skill publish is in progress.)

State the request, budget, and profile

You
"Source a game-ready crate, max 0.50 test USDC, grade against sample-game-prop@1." (Want a tighter bar? name the private game-ready-prop@1, or hand the Mind your own inline profile.)
Your Mind
Turns intent into a spec + budget + profile reference; asks 1–2 clarifying questions if needed.
Result
The profileId selects which deterministic predicates fire and their thresholds; a BYO inline profile works too, with no registration.
Safety
The private tuned thresholds live in the Grader Mind's memory — never in your prompt or the public repo. The public sample-game-prop@1 is open by design.

Generate a candidate

You
Approve generating within budget.
Your Mind
generate_asset produces a GLB (commodity image/text→3D, e.g. a fal Rodin path) and, for a profile that requires it, attaches the declared editable params so named_params is meaningful. Generation is generation-agnostic — Grain grades whatever bytes arrive.
Result
A GLB whose bytes — and the assetHash the verdict commits to — are deterministic (params sorted).
Safety
Generation is commodity; Grain owns verification, not making.

Grade (signed verdict)

You
— (autonomous)
Your Mind
grade_asset parses once, runs the predicates in sorted order (+ semantic_match if an intent is given), composes pass/fail (AND, or weighted per profile), computes predicateDigest, and signs the verdict when an escrowId is supplied.
Result
{ pass, results[], predicateDigest, assetHash, verdict }. No escrowIdverdict: null (grade-only).
Safety
The verdict is decided by deterministic code, never the LLM; re-grading is byte-identical.

Review the pass/fail + evidence

You
Read the verdict table before money moves.
Your Mind
Shows each predicate's id, pass/fail, and evidence (triangleCount; boundary/non-manifold edges; GLB errors; declared/required/missing params; topMatch/score).
Result
This is the "preview" gate — the legible "show the no."
Safety
Never rubber-stamp a near-margin semantic score; surface low confidence honestly.

Confirm settlement (gated), then monitor

You
The gate is upstream at funding; pick the rail, then monitor the returned transaction.
Your Mind
settle submits the canonical verdict to the chosen rail — settleOnAttestation(escrowId, result, assetHash, graderSignature) on the Base Sepolia escrow, or the equivalent ed25519-verified instruction on the Solana devnet program: a pass releases to the seller, a fail refunds the buyer.
Result
OrderReleased / OrderRefunded on Base Sepolia, or the equivalent settled state on Solana devnet — the same verdict, either chain.
Safety
No human approval needed — the signed verdict IS the gate; the keeper pays gas but can't redirect funds. Verify the receipt status: tx inclusion is not tx success.
06

Settlement: how one signed verdict releases money across three testnet chains

Grain's settlement layer sits behind a chain-neutral SettlementAdapter seam, and that seam now has two implementations (EVM and Solana) — both consuming the same canonical verdict, live across three chains. The EVM rail is a single verification-gated contract, GrainEscrow, deployed on Base Sepolia (chainId 84532) at 0xEEb15426d656dCfb76AC058D1A1e66c821cB78d9 and on BNB Chain testnet (chainId 97) at 0x300Aa36E9b19F2ea4F9eDb6415788C7912e54162, settling test USDC (on Base, Circle test USDC 0x036CbD53842c5426634e7929541eC2318f3dCF7e, 6 decimals). On the EVM rail the lifecycle is three moves:

  1. Fund. The buyer calls fundOrder(escrowId, seller, grader, amount, specHash). This pulls amount USDC in and records the order write-once: buyer = msg.sender, the seller, the grader (the only signer whose verdict counts for this order), and the specHash.
  2. Grade + sign. Off-chain, the grader signs the verdict. The signature is EIP-191 personal_sign over the digest below; the runtime reproduces it byte-for-byte, so the off-chain signature is exactly what the contract recovers.
  3. Settle. Anyone — in practice a keeper — calls settleOnAttestation(escrowId, result, assetHash, graderSignature). The contract recovers the signer and requires it to equal the order's recorded grader, else it reverts with bad grader sig. On pass it pays seller; on fail it refunds buyer.
digest = keccak256(abi.encode(
  "Grain settleOnAttestation",
  escrowId, uint8(result), assetHash,
  address(this),      // this exact contract
  block.chainid       // this exact chain (84532)
))
// signed EIP-191 personal_sign; recovered signer must == order.grader
  • The keeper pays gas and has zero authority. Recipients are fixed on-chain, so it can't redirect funds; the runtime treats a reverted-but-included transaction as a hard failure (it waits for the receipt and throws unless status === 'success').
  • The signature can't be replayed. The digest binds the verdict to this order, this result, this exact asset (assetHash), this contract, and this chain — a pass can't be replayed as a fail, asset A's signature can't settle asset B, and another instance or chain is rejected. Each binding has a dedicated test.
  • Hardened. ReentrancyGuard + checks-effects-interactions (state committed before transfer) + one-shot (the Status.Funded guard means a settled order can't settle twice).
Live status

Four autonomous rounds (fail → refund, pass → release, fail → refund, pass → release) ran end-to-end against the Base Sepolia deployment with no human in the loop, plus the full Hardhat suite covering the custody boundary, signature binding, one-shot, and reentrancy. The same EVM contract is also live on BNB Chain testnet with a verified on-chain release. The Solana devnet program is deployed and its settle path is verified on-chain via npm run solana:settle (ed25519 verdict, same canonical tuple). (An existence proof of the loop across all three chains, not a reliability statistic; the contracts have tests + live testnet runs, not a third-party audit.)

The second rail — Solana devnet (ed25519)

The same canonical verdict also settles on Solana. An Anchor program in contracts-solana/ is deployed and live on Solana devnet at program id 4EDeeLJNbh9AXdLsfkgHswJ9VS2RX7yad9wV9pU7Ebgs, with a TypeScript adapter (packages/runtime/src/solana-adapter.ts) that defaults to that program id. Instead of recovering an EIP-191 signature to an address, the program verifies an ed25519 signature against the order's recorded grader pubkey. The signed message binds the same fields — DOMAIN || order_id || result || asset_hash || program_id || cluster — so the verdict is just as replay-bound as on EVM (a pass can't be replayed as a fail; another program or cluster is rejected). You can prove the round-trip on devnet with npm run solana:settle.

// EVM digest (recovered signer must == order.grader address)
digest = keccak256(abi.encode(
  "Grain settleOnAttestation",
  escrowId, uint8(result), assetHash,
  address(this), block.chainid))      // this contract, chainId 84532

// Solana message (ed25519, verified against order.grader pubkey)
msg = DOMAIN || order_id || result || asset_hash || program_id || cluster
//   one canonical verdict { escrowId, result, assetHash, graderSignature }
//   → either adapter consumes it; the sign-only key can never pay itself on either chain

Mainnet path (roadmap, not built). On mainnet the same EVM contract would point at bridged USDC and the Solana program at a mainnet cluster; no mainnet deployment exists on either rail. Both adapters are real today — EVM live on Base Sepolia and BNB Chain testnet, Solana live on devnet — and the SettlementAdapter seam means a third rail is a new adapter, not a re-architecture.

07

Operating it: verify on-chain first, keep the audit trail, then revoke and stop

Everything you need to manage a live connection is verifiable on-chain — read first, trust nothing you haven't checked.

Verify status by on-chain reads

Read orders(escrowId) and the status byte: 0 None, 1 Funded, 2 Released, 3 Refunded. To confirm a settlement actually happened, watch the events — OrderReleased and OrderRefunded each carry escrowId, the recipient, the amount, the assetHash, and the settler (the keeper). Don't report a settlement off the keeper's optimism; confirm it landed in state and in an event.

Keep the audit trail

  • assetHash — the sha256 of the exact GLB bytes the grader judged, baked into the signed digest and recorded in the event, so any payout is provably tied to one specific artifact.
  • predicateDigest — a sha256 over the sorted, timestamp- and evidence-excluded predicate results, so re-grading the same asset later proves you got the same verdict.
  • Keep the (escrowId, assetHash, predicateDigest, tx hash) tuple per order — that is your durable record.

Verify the grader, then revoke and stop

The order records the grader whose signature is the only one honored — an address on the EVM rail, a pubkey on Solana. The public signer in the EVM deployment is 0xB89e1Aba9c23f8227f29d3727570526e3Dd7C5Ee — the public address (the Solana rail records the grader pubkey analogously); the private key never leaves the grader and is never in source or logs. Because the contract has no owner, pause, or withdraw, you don't "turn off" the escrow — you stop feeding it: stop the keeper (no keeper → no settlement), stop funding new orders, and fund any future order with a rotated grader address. Drain funded orders first — stopping the keeper strands an already-funded order until a valid grader signature settles it. Released/Refunded orders are final. There is no sweep and no admin escape hatch — which is the point: no admin attack surface.

08

Troubleshooting

The rule that overrides everything

Never report a pass/fail or "settled" state you have not verified against a signed deterministic verdict and an on-chain receipt. If the grader has no deterministic tool evidence, it must not emit a verdict; if the settle transaction hasn't confirmed success, it must not report "settled."

SymptomLikely causeWhat the Mind should checkFix
A Mind never replies / a step hangs (no narration) Cognition balance is 0 (silent timeout), or a fresh-Mind top-up charged without minting credits (balance is not real-time) Hard-refresh the builder UI to read the real balance; was the top-up done immediately after creating the Mind? Fund cognition and hard-refresh; if a fresh-Mind top-up didn't mint, fund again after the wallet registers. Narration is flavor-only — a Mind timeout must never block settlement (the signed verdict is the sole gate).
Verdict won't settle (tx reverts) Bad/missing grader signature, wrong rail binding (EVM escrowAddress/chainId vs Solana programId/cluster), grader mismatch (address vs pubkey), or the order is already settled / not settleable Did grade_asset return a non-null signed verdict (an escrowId was supplied)? Does the verdict's chain binding match the rail you're settling on — EVM 0xEEb1…78d9 / 84532, or Solana program 4EDee…Ebgs / devnet? On-chain order status? Re-grade WITH the correct escrowId and the right rail binding for a fresh signature; don't retry a settle on a Released/Refunded order. A returned tx hash ≠ success — a non-success receipt (EVM) or failed instruction (Solana) is a hard failure.
Asset fails unexpectedly Graded against the wrong profile (e.g. the strict private game-ready-prop@1 instead of the public sample-game-prop@1), missing UVs, an oversized texture, or declared params missing (named_params) — not always a topology defect The per-predicate evidence: uv_present UV channel; texture_size px vs budget; file_size bytes vs budget; tri_count vs budget; manifold boundary/non-manifold edges; valid_glb errors; named_params declared/required/missing. Confirm the right profileId (or pass a BYO inline profile), then fix the named predicate — unwrap UVs, resize the texture into budget, weld + simplify, or attach the required params. A genuine non-manifold or unwrapped asset should fail — that's the grader correctly saying "no."
semantic_match fails or is borderline The asset doesn't match the intent, or the score is near the threshold (calibrated T ≈ 0.5–0.6; less-distinctive shapes like the barrel score ~75% — figures from the honest-v0 N=5 benchmark, which proves the method + floor, not the hard/confusable cases) topMatch, intentScore, and the per-label scores in the evidence. If topMatch is a distractor, the fail is correct; if near-margin, treat it as low-confidence and say so. Do not raise the threshold to force a pass.
Skill not callable / tool errors The Skill isn't equipped, or the Connection holding the grading key is missing/misconfigured Is "Grain 3D Conformance Grader" equipped? Is the Connection attached and valid? Are secrets in Connections (not chat)? Attach/repair the Connection, then re-grade a known profile. Skill edits apply to NEW sessions — start a fresh session to pick up a fixed version.
Skill behaves like an old version after an edit Published Skills are live but versioned — in-flight sessions keep their version Are you in the same session where the edit was made? Start a new session to pick up the updated Skill (REGISTRY_Update / SKILL_Update apply to new sessions).