Banked: 2026-06-11 (SEAMS lane, 24h-rule follow-up resolving the prior PT-linear-discount lesson's STAGE-candidate hypothesis) Status: scoping-boundary calibration. WALK-CLEAN. Closes the open "probe Spark's deployment next" thread.
The prior lesson (pt-linear-discount-oracle-seam) said: "linear-discount + missing depeg feed on Morpho = advisory; the SAME config inside a permissioned, governance-listed protocol (SparkLend/Sky) WOULD be a protocol finding - go probe Spark next."
Probed Spark. Resolution: Spark does NOT wire PT + the linear oracle into its in-scope governance-permissioned lending pool. It keeps ALL PT exposure inside a SEPARATE MetaMorpho vault on permissionless Morpho Blue. A governance entity (SparkDAO) curating a permissionless venue does NOT convert curator-risk into a protocol finding. The scope boundary is the VENUE/ENGINE the param lives in, not the identity of who set it.
The prior rule asked "who chose the oracle - anonymous creator or governance?" That is necessary but NOT sufficient. The sharper rule:
WALK-vs-STAGE hinges on the ENGINE the parameter lives in, not the chooser's identity:
- Param on the protocol's OWN in-scope contract (e.g. a SparkLend Aave-fork reserve listed by POOL_CONFIGURATOR) -> protocol owns it -> in-scope candidate.
- Param on a permissionless THIRD-PARTY engine (Morpho Blue market / MetaMorpho vault), even if a governance DAO is the curator -> the third-party engine's permissionless model governs scope -> curator-risk -> WALK for the DAO's own program.
A DAO can wear two hats: (1) protocol-governor of its own contracts (in-scope), (2) curator/allocator on someone else's permissionless rails (out-of-scope, accepted-risk model). Resolve WHICH hat before STAGE.
getReservesList() for Aave-forks). If it has no PT, mechanism (a) is dead - the conservative governance collateral set is itself the mitigation.0x73e65DBD630f90604062f6E02fAb9138e713edD9 (owner = SparkDAO proxy 0x3300f198988e4C9C63F75dF86De36421f06af8c4) on Morpho Blue 0xBBBB...FFCb. Enumerate withdrawQueue -> idToMarketParams -> flag PT collateral, read the oracle's BASE_FEED_1/2.0xC13e21B648A5Ee794902342038FF3aDAB66BE987 - 18 reserves, conservative, NO PT.0x73e65DBD630f90604062f6E02fAb9138e713edD9.baseDiscountPerYear() + maturity() and lacks market()/twapDuration(). Matured iff maturity() <= block.timestamp -> returns 1e18.BASE_FEED_2() == address(0) AND QUOTE_FEED_1() == address(0) -> both sides hardcoded $1.cast against ethereum-rpc.publicnode.com; vault allocations via blue-api.morpho.org/graphql vaultByAddress.