@@ -76,6 +76,18 @@ safetyLevelLabel EpistemicSafe = "L10:EpistemicSafe"
7676-- Type Compatibility (decidable boolean check for Level 2)
7777-- ═══════════════════════════════════════════════════════════════════════
7878
79+ ||| Structural equality for Agent (ignoring payload for parameterised agents).
80+ ||| Top-level so every `vqlTypeEq` clause can use it (a `where` binding is
81+ ||| only in scope for the single clause it is attached to).
82+ public export
83+ agentEq : Agent -> Agent -> Bool
84+ agentEq AgEngine AgEngine = True
85+ agentEq (AgProver a) (AgProver b) = a == b
86+ agentEq AgValidator AgValidator = True
87+ agentEq (AgUser a) (AgUser b) = a == b
88+ agentEq AgFederation AgFederation = True
89+ agentEq _ _ = False
90+
7991||| Decidable structural equality for VqlType.
8092||| Returns True when two types are the same constructor with matching
8193||| arguments — used by Level 2 to verify comparison operand types.
@@ -97,15 +109,6 @@ vqlTypeEq (TKnows a1 t1) (TKnows a2 t2) = agentEq a1 a2 && vqlTypeEq t1 t2
97109vqlTypeEq (TBelieves a1 t1) (TBelieves a2 t2) = agentEq a1 a2 && vqlTypeEq t1 t2
98110vqlTypeEq (TCommonKnowledge t1) (TCommonKnowledge t2) = vqlTypeEq t1 t2
99111vqlTypeEq _ _ = False
100- where
101- ||| Structural equality for Agent (ignoring payload for parameterised agents).
102- agentEq : Agent -> Agent -> Bool
103- agentEq AgEngine AgEngine = True
104- agentEq (AgProver a) (AgProver b) = a == b
105- agentEq AgValidator AgValidator = True
106- agentEq (AgUser a) (AgUser b) = a == b
107- agentEq AgFederation AgFederation = True
108- agentEq _ _ = False
109112
110113||| Check whether two VqlTypes are compatible for comparison.
111114|||
@@ -134,46 +137,65 @@ typesCompatible a b =
134137-- Field Reference Extraction
135138-- ═══════════════════════════════════════════════════════════════════════
136139
137- ||| Recursively extract all FieldRef nodes from an expression tree.
138- ||| Traverses EField, ECompare, ELogic, EAggregate, and ESubquery nodes.
139- public export
140- extractFieldRefs : Expr -> List FieldRef
141- extractFieldRefs (EField ref _ ) = [ref]
142- extractFieldRefs (ELiteral _ _ ) = []
143- extractFieldRefs (ECompare _ l r _ ) = extractFieldRefs l ++ extractFieldRefs r
144- extractFieldRefs (ELogic _ l Nothing _ ) = extractFieldRefs l
145- extractFieldRefs (ELogic _ l (Just r) _ ) = extractFieldRefs l ++ extractFieldRefs r
146- extractFieldRefs (EAggregate _ e _ ) = extractFieldRefs e
147- extractFieldRefs (EParam _ _ ) = []
148- extractFieldRefs EStar = []
149- extractFieldRefs (ESubquery sub) = statementFieldRefs sub
150- extractFieldRefs (EEpistemic _ _ e _ ) = extractFieldRefs e
151- extractFieldRefs (EAnnounce _ prop body _ ) =
152- extractFieldRefs prop ++ extractFieldRefs body
153-
154- ||| Collect all field references from every clause of a statement.
155- ||| Delegates to extractFieldRefs for each expression-bearing clause.
156- public export
157- statementFieldRefs : Statement -> List FieldRef
158- statementFieldRefs stmt =
159- let selRefs : List FieldRef
160- selRefs = concatMap selItemFieldRefs (selectItems stmt)
161- whereRefs : List FieldRef
162- whereRefs = maybe [] extractFieldRefs (whereClause stmt)
163- groupRefs : List FieldRef
164- groupRefs = groupBy stmt
165- havingRefs : List FieldRef
166- havingRefs = maybe [] extractFieldRefs (having stmt)
167- orderRefs : List FieldRef
168- orderRefs = map fst (orderBy stmt)
169- in selRefs ++ whereRefs ++ groupRefs ++ havingRefs ++ orderRefs
170- where
171- ||| Extract field references from a single SELECT item.
172- selItemFieldRefs : SelectItem -> List FieldRef
173- selItemFieldRefs (SelField ref) = [ref]
174- selItemFieldRefs (SelModality _ ) = []
175- selItemFieldRefs (SelAggregate _ e) = extractFieldRefs e
176- selItemFieldRefs SelStar = []
140+ mutual
141+ ||| Recursively extract all FieldRef nodes from an expression tree.
142+ ||| Traverses EField, ECompare, ELogic, EAggregate, and ESubquery nodes.
143+ |||
144+ ||| Mutually recursive with `statementFieldRefs` through `ESubquery`.
145+ ||| All recursion is explicit structural descent (no `concatMap`/`maybe`/
146+ ||| `map`) so the totality checker can see it terminates — every callee
147+ ||| is applied to a strict sub-term of the constructor argument.
148+ public export
149+ extractFieldRefs : Expr -> List FieldRef
150+ extractFieldRefs (EField ref _ ) = [ref]
151+ extractFieldRefs (ELiteral _ _ ) = []
152+ extractFieldRefs (ECompare _ l r _ ) = extractFieldRefs l ++ extractFieldRefs r
153+ extractFieldRefs (ELogic _ l Nothing _ ) = extractFieldRefs l
154+ extractFieldRefs (ELogic _ l (Just r) _ ) = extractFieldRefs l ++ extractFieldRefs r
155+ extractFieldRefs (EAggregate _ e _ ) = extractFieldRefs e
156+ extractFieldRefs (EParam _ _ ) = []
157+ extractFieldRefs EStar = []
158+ extractFieldRefs (ESubquery sub) = statementFieldRefs sub
159+ extractFieldRefs (EEpistemic _ _ e _ ) = extractFieldRefs e
160+ extractFieldRefs (EAnnounce _ prop body _ ) =
161+ extractFieldRefs prop ++ extractFieldRefs body
162+
163+ ||| Extract field references from a SELECT-item list (explicit recursion).
164+ public export
165+ selItemsFieldRefs : List SelectItem -> List FieldRef
166+ selItemsFieldRefs [] = []
167+ selItemsFieldRefs (SelField ref :: rest) = ref :: selItemsFieldRefs rest
168+ selItemsFieldRefs (SelModality _ :: rest) = selItemsFieldRefs rest
169+ selItemsFieldRefs (SelAggregate _ e :: rest) =
170+ extractFieldRefs e ++ selItemsFieldRefs rest
171+ selItemsFieldRefs (SelStar :: rest) = selItemsFieldRefs rest
172+
173+ ||| Field refs of an optional clause expression (explicit, no `maybe`).
174+ public export
175+ optExprFieldRefs : Maybe Expr -> List FieldRef
176+ optExprFieldRefs Nothing = []
177+ optExprFieldRefs (Just e) = extractFieldRefs e
178+
179+ ||| Projection of an ORDER BY list to its field refs (explicit, no `map`).
180+ public export
181+ orderByFieldRefs : List (FieldRef, Bool ) -> List FieldRef
182+ orderByFieldRefs [] = []
183+ orderByFieldRefs ((f, _ ) :: xs) = f :: orderByFieldRefs xs
184+
185+ ||| Collect all field references from every clause of a statement.
186+ ||| Delegates to extractFieldRefs for each expression-bearing clause.
187+ ||| Pattern-matches the `MkStatement` constructor rather than using field
188+ ||| projections so the totality checker sees each clause as a strict
189+ ||| sub-term of the statement (record projections defeat the size check
190+ ||| across the `ESubquery` mutual edge).
191+ public export
192+ statementFieldRefs : Statement -> List FieldRef
193+ statementFieldRefs (MkStatement sel _ whr grp hav ord _ _ _ _ _ _ _ _ ) =
194+ selItemsFieldRefs sel
195+ ++ optExprFieldRefs whr
196+ ++ grp
197+ ++ optExprFieldRefs hav
198+ ++ orderByFieldRefs ord
177199
178200-- ═══════════════════════════════════════════════════════════════════════
179201-- Expression Scanning Helpers
@@ -617,11 +639,14 @@ runPipeline (lvl :: rest) stmt schema state =
617639||| @schema The VeriSimDB octad schema to validate against.
618640||| @return A CheckResult with the achieved safety level and diagnostics.
619641public export
620- checkQuery : Statement -> OctadSchema -> CheckResult
642+ checkQuery : Statement -> OctadSchema -> Checker. CheckResult
621643checkQuery stmt schema =
622644 let initState : PipelineState
623645 initState = MkPipelineState ParseSafe [] []
624- (finalState, mFailure) = runPipeline allLevels stmt schema initState
646+ res : (PipelineState, Maybe String)
647+ res = runPipeline allLevels stmt schema initState
648+ finalState : PipelineState
649+ finalState = fst res
625650 in case finalState. passed of
626651 [] =>
627652 -- Level 0 itself failed — should not happen (ParseSafe always passes)
0 commit comments