PostgreSQL : inconsistent result when using WHERE clause on VIEW
The effect of ORDER BY is only mandatory on the same query level.
Your view acts as derived table and if you just SELECT * FROM inv_groups_vw, the order is preserved.
However, when adding another WHERE clause to the outer SELECT, you would have to add ORDER BY to the outer query as well.
In your particular case, the order of rows is not guaranteed, even for the simple query:
SELECT * FROM inv_groups_vw

Since the only ORDER BY in the view is in a subquery itself. It's an implementation detail that the sort order happens to be preserved. That can change any time without notice.
More importantly, your objective seems to be to order the values in items, which is a related, but different issue.
Complete rewrite
After feedback from your comments I think this should be best to fulfill your requirement:

items (i.e. array_agg(i)) are REQUIRED to be ordered by item_index.

CREATE OR REPLACE VIEW inv_groups_vw AS 
SELECT g.id,
       g.sku,
       g.name,
       g.description,
       CASE
          WHEN count(i.id) = 0 THEN '[]'::json
          ELSE json_agg(i ORDER BY m.item_index)
       END AS items
FROM   inv_items                    g
LEFT   JOIN inv_items_group_members m ON m.group_id = g.id
LEFT   JOIN inv_items               i ON i.id = m.item_id
                                     AND NOT i.is_group
WHERE  g.is_group
GROUP  BY g.id;    -- assuming g.id is the pk!