machine_id!==$m['machine_id']) throw new RuntimeException('Manifest machine mismatch'); $plans=App\Models\Plan::whereIn('id',$ids)->orderBy('id')->get(['id','group_id']); if ($plans->count()!==count($ids)) throw new RuntimeException('Some selected plans missing'); if ($group!==null) App\Models\ServerGroup::findOrFail($group); $result=[ 'node_id'=>$node->id, 'name'=>$node->name, 'is_online'=>(bool)$node->is_online, 'last_check_at'=>$node->last_check_at, 'last_push_at'=>$node->last_push_at, 'group_ids'=>$node->group_ids, 'qa_upload'=>(int)$qa->u, 'qa_download'=>(int)$qa->d, 'qa_banned'=>(bool)$qa->banned, 'selected_plan_ids'=>$ids, 'plans'=>$plans->toArray(), 'existing_users_with_selected_plan_and_null_group'=>$ids ? App\Models\User::whereIn('plan_id',$ids)->whereNull('group_id')->count() : null, 'selected_plans_in_other_group'=>$group===null ? null : $plans->filter(fn($p) => $p->group_id!==null && (int)$p->group_id!==$group)->pluck('id')->all(), 'scope'=>'Read-only snapshot; not subscription/traffic/GUI acceptance', ]; echo json_encode($result,JSON_THROW_ON_ERROR|JSON_UNESCAPED_UNICODE).PHP_EOL; } catch (Throwable $e) { fwrite(STDERR,"Readiness failed; verify parameters and manifest.\n"); exit(1); }