The issue is that Firestore security rules are not filters. Be sure to read and understand that documentation, as well as this post. Your query is asking for all of the documents in the Routines collection. Security rules will either allow that request for all documents, or reject it entirely. They will not provide a subset of those documents that match some criteria. If security rules will not scan the contents of all documents to check their values - that will not scale massively as Firestore requires.
There is unfortunately a second problem here in that there is actually no way to make your query match your rules. Firestore doesn't provide a way to filter for the existence of a field in documents. You can only filter on known field values that actually exist. This means that you should consider alternatives to your data modeling. Perhaps you want to add a boolean field called "hasProgramId" and make sure it always has a value of true or false so that it can be used in both rules and query filters.
So your query could be like this:
const res = await firebase.firestore()
.collection("Routines")
.where("hasProgramId", "==", true)
.get();
And your rules can check to make sure the client request is valid like this:
match /Routines/{routineId=**} {
allow write: if false;
allow read: if resource.data.hasProgramId;
}