diff --git a/dhscanner-kbgen.cabal b/dhscanner-kbgen.cabal
--- a/dhscanner-kbgen.cabal
+++ b/dhscanner-kbgen.cabal
@@ -1,99 +1,99 @@
-cabal-version:      3.12
-name:               dhscanner-kbgen
-category:           parsing
-synopsis:           knowledge base predicates for static code analysis
-description:
-
-    * The [knowledge base](https://en.wikipedia.org/wiki/Knowledge_representation_and_reasoning) ( kb )
-      aims to be a data structure able to:
-
-        * represent /multiple/ facts about the source code repo
-        * from /various/ programming languages
-        * each fact can be translated to a [Prolog](https://en.wikipedia.org/wiki/Prolog) fact
-        * facts can be combined to create [predicates](https://en.wikipedia.org/wiki/Predicate_%28logic%29)
-        * predictaes can be combined to formulate /security queries/
-
-    * [Prolog](https://en.wikipedia.org/wiki/Prolog) facts describe relations between:
-
-        * code locations
-        * const strings
-        * const integers
-
-    * [Prolog](https://en.wikipedia.org/wiki/Prolog) facts can be /combined/:
-
-        * create /expressive/ queries from /simple/ facts
-        * [conjunction](https://en.wikipedia.org/wiki/Logical_conjunction)
-        * [disjunction](https://en.wikipedia.org/wiki/Logical_disjunction)
-        * [negation](https://en.wikipedia.org/wiki/Negation)
-
-    * [Prolog](https://en.wikipedia.org/wiki/Prolog) queries are /easy/ to write:
-
-        * you /don't/ have to be a Prolog expert
-        * copy-paste the basic facts to /any/ [LLM](https://en.wikipedia.org/wiki/Large_language_model)
-        * explain in plain English your query's purpose
-        * et voilà !
-
-version:            2.1.1
-license:            GPL-3.0-only
-license-file:       LICENSE
-author:             OrenGitHub
-maintainer:         Oren Ish Shalom
-copyright:          (c) 2025 Oren Ish Shalom
-homepage:           https://github.com/OrenGitHub/dhscanner
-stability:          experimental
-build-type:         Simple
-
-common ghc_options
-
-    ghc-options: -Wall -Werror=incomplete-patterns -O2
-
-library
-
-    import:
-        ghc_options
-
-    exposed-modules:
-        Kbgen
-
-    build-depends:
-        aeson >= 2.2 && < 2.4,
-        attoparsec >= 0.14 && < 0.15,
-        filepath >= 1.4 && < 1.6,
-        base >= 4.22 && < 4.23,
-        containers >= 0.8 && < 0.9,
-        text >= 2.0 && < 2.2,
-        dhscanner-ast >= 1.3.1 && < 1.4,
-        dhscanner-bitcode >= 2.1.1 && < 2.2
-
-    hs-source-dirs:
-        src
-
-    default-language:
-        GHC2024
-
-test-suite restoreloc
-
-    import:
-        ghc_options
-
-    type:
-        exitcode-stdio-1.0
-
-    hs-source-dirs:
-        test
-
-    main-is:
-        Test.hs
-
-    other-modules:
-        SmokeTests
-
-    build-depends:
-        base,
-        dhscanner-kbgen,
-        dhscanner-ast,
-        hspec,
-        QuickCheck
-
-    default-language:
-        GHC2024
+cabal-version:      3.12
+name:               dhscanner-kbgen
+category:           parsing
+synopsis:           knowledge base predicates for static code analysis
+description:
+
+    * The [knowledge base](https://en.wikipedia.org/wiki/Knowledge_representation_and_reasoning) ( kb )
+      aims to be a data structure able to:
+
+        * represent /multiple/ facts about the source code repo
+        * from /various/ programming languages
+        * each fact can be translated to a [Prolog](https://en.wikipedia.org/wiki/Prolog) fact
+        * facts can be combined to create [predicates](https://en.wikipedia.org/wiki/Predicate_%28logic%29)
+        * predictaes can be combined to formulate /security queries/
+
+    * [Prolog](https://en.wikipedia.org/wiki/Prolog) facts describe relations between:
+
+        * code locations
+        * const strings
+        * const integers
+
+    * [Prolog](https://en.wikipedia.org/wiki/Prolog) facts can be /combined/:
+
+        * create /expressive/ queries from /simple/ facts
+        * [conjunction](https://en.wikipedia.org/wiki/Logical_conjunction)
+        * [disjunction](https://en.wikipedia.org/wiki/Logical_disjunction)
+        * [negation](https://en.wikipedia.org/wiki/Negation)
+
+    * [Prolog](https://en.wikipedia.org/wiki/Prolog) queries are /easy/ to write:
+
+        * you /don't/ have to be a Prolog expert
+        * copy-paste the basic facts to /any/ [LLM](https://en.wikipedia.org/wiki/Large_language_model)
+        * explain in plain English your query's purpose
+        * et voilà !
+
+version:            2.1.2
+license:            GPL-3.0-only
+license-file:       LICENSE
+author:             OrenGitHub
+maintainer:         Oren Ish Shalom
+copyright:          (c) 2025 Oren Ish Shalom
+homepage:           https://github.com/OrenGitHub/dhscanner
+stability:          experimental
+build-type:         Simple
+
+common ghc_options
+
+    ghc-options: -Wall -Werror=incomplete-patterns -O2
+
+library
+
+    import:
+        ghc_options
+
+    exposed-modules:
+        Kbgen
+
+    build-depends:
+        aeson >= 2.2 && < 2.4,
+        attoparsec >= 0.14 && < 0.15,
+        filepath >= 1.4 && < 1.6,
+        base >= 4.22 && < 4.23,
+        containers >= 0.8 && < 0.9,
+        text >= 2.0 && < 2.2,
+        dhscanner-ast >= 1.3.1 && < 1.5,
+        dhscanner-bitcode >= 2.1.1 && < 2.3
+
+    hs-source-dirs:
+        src
+
+    default-language:
+        GHC2024
+
+test-suite restoreloc
+
+    import:
+        ghc_options
+
+    type:
+        exitcode-stdio-1.0
+
+    hs-source-dirs:
+        test
+
+    main-is:
+        Test.hs
+
+    other-modules:
+        SmokeTests
+
+    build-depends:
+        base,
+        dhscanner-kbgen,
+        dhscanner-ast,
+        hspec,
+        QuickCheck
+
+    default-language:
+        GHC2024
diff --git a/src/Kbgen.hs b/src/Kbgen.hs
--- a/src/Kbgen.hs
+++ b/src/Kbgen.hs
@@ -1,1514 +1,1515 @@
--- |
---
--- * The [knowledge base](https://en.wikipedia.org/wiki/Knowledge_representation_and_reasoning) ( kb )
---   aims to be a data structure able to:
---
---     * represent /multiple/ facts about the source code repo
---     * from /various/ programming languages
---     * each fact can be translated to a [Prolog](https://en.wikipedia.org/wiki/Prolog) fact
---     * facts can be combined to create [predicates](https://en.wikipedia.org/wiki/Predicate_%28logic%29)
---     * [predicates](https://en.wikipedia.org/wiki/Predicate_%28logic%29) can be combined to formulate /security queries/
---
--- * Facts describe relations between:
---
---     * code locations
---     * const strings
---     * const integers
---
--- * Code locations are capable of representing /all/ program entities
---
---     * classes
---     * methods
---     * lambdas
---     * annotations
---     * arguments
---     * parameters
---     * etc.
---
--- * Facts can be /combined/:
---
---     * [conjunction](https://en.wikipedia.org/wiki/Logical_conjunction)
---     * [disjunction](https://en.wikipedia.org/wiki/Logical_disjunction)
---     * [negation](https://en.wikipedia.org/wiki/Negation)
---
--- * [Prolog](https://en.wikipedia.org/wiki/Prolog) queries are /easy/ to write:
---
---     * you /don't/ have to be a Prolog expert
---     * copy-paste the basic facts to /any/ [LLM](https://en.wikipedia.org/wiki/Large_language_model)
---     * explain in plain English your query's purpose
---     * et voilà !
---
--- * Its main purpose is to serve as the:
---
---     * penultimate step for /static code analysis/ 
---     * part of the [dhscanner](https://github.com/OrenGitHub/dhscanner.vps) framework
---
---         * [SAST](https://en.wikipedia.org/wiki/Static_application_security_testing) for security scans 🔒
---         * [PII](https://en.wikipedia.org/wiki/Personal_data) leaks detection 🪪
---
-
-{-# LANGUAGE DeriveGeneric #-}
-{-# LANGUAGE DeriveAnyClass #-}
-{-# LANGUAGE OverloadedStrings #-}
-
-module Kbgen (
-    KeywordArgForCall(..),
-    ParamResolvedType(..),
-    ClassDef(..),
-    FuncDef(..),
-    Call1stPartyFuncDefinedInDir(..),
-    AssignValueToToplevelVarName(..),
-    Call1stPartyFuncDefinedInFile(..),
-    ParamName(..),
-    CallMethodOfClass(..),
-    ConstString(..),
-    ConstInteger(..),
-    MethodOfClass(..),
-    ClassHas1stPartySuper(..),
-    ClassHas3rdPartySuper(..),
-    CallMethodOfUntypedNamedParam(..),
-    ArgiForCall(..),
-    DataflowEdge(..),
-    ConstBoolTrue(..),
-    ConstNull(..),
-    GatedReturn(..),
-    Comparison(..),
-    CallableReturnsValue(..),
-    CallableReturnsWithoutValue(..),
-    Cond(..),
-    Lhs(..),
-    Rhs(..),
-    ComparisonOp(..),
-    ReturnedValue(..),
-    ClassAnnotation,
-    CallableAnnotation,
-    CallableSourceBodyLength(..),
-    ParamiOfCallable(..),
-    prologify,
-    To(..),
-    Arg(..),
-    From(..),
-    Func(..),
-    Call(..),
-    Class(..),
-    Param(..),
-    Method(..),
-    Callable(..),
-    Keyword(..),
-    Resolved(..),
-    ArgIndex(..),
-    ParamIndex(..),
-    FuncName(..),
-    MethodName(..),
-    ResolvedType(..),
-    CallResolved(..),
-    CalledFrom(..),
-    AssignedValue(..),
-    ResolvedSuper(..),
-    FuncDefinedInDir(..),
-    FuncDefinedInFile(..),
-    ClassDefinedInFile(..),
-    SuperDefinedInFile(..),
-    SuperQualifiedName(..),
-    ConstStr(..),
-    ConstInt(..),
-    Fact(..),
-    locationify,
-    restoreloc
-)
-
-where
-
--- general imports
-import Data.Aeson
-import Text.Printf
-import GHC.Generics (Generic)
-import System.FilePath (takeDirectory)
-import Data.Attoparsec.Text (Parser, char, decimal, parseOnly, string, takeText)
-import Data.Text (Text)
-import qualified Data.Text as T
-
--- general qualified imports
-import qualified Data.List as List
-
--- project imports
-import Location
-import qualified Token
-import qualified Fqn
-
--- |
---
--- __Name__
---
--- This is how the fact will look inside the Prolog file
---
--- @
--- kb_keyword_arg_for_call( Keyword, Arg, Call ).
--- @
---
--- __When should I use this fact__ ( motivation: [CVE-2024-52803](https://nvd.nist.gov/vuln/detail/CVE-2024-52803) )
---
--- Code snippet ( Python ):
---
--- @
--- Popen(f'llamafactory-cli train {save_cmd(args)}', env=env, shell=True)
--- @
---
--- See complete source example: [here](https://github.com/hiyouga/LLaMA-Factory/commit/b3aa80d54a67da45e9e237e349486fb9c162b2ac)
---
--- __Writing a predicate with this fact and others__ ( motivation: [CVE-2024-52803](https://nvd.nist.gov/vuln/detail/CVE-2024-52803) )
---
--- @
--- subprocess_Popen_called_with_shell_eq_True( Call ) :-
---     kb_keyword_arg_for_call( \'shell\', TrueValue, Call ),
---     kb_call_resolved( Call, \'subprocess.Popen\' ),
---     kb_const_bool_true( TrueValue ).
--- @
---
--- Other facts combined in this example predicate:
---
---     * 'CallResolved'
---     * 'ConstBoolTrue'
---
-data KeywordArgForCall = KeywordArgForCall
-    Keyword -- ^
-    Arg -- ^
-    Call -- ^
-    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
--- |
---
--- __Name__
---
--- This is how the fact will look inside the Prolog file
---
--- @
--- kb_param_has_resolved_type( Param, ResolvedType ).
--- @
---
--- __When should I use this fact__ ( motivation: [CVE-2024-49380](https://nvd.nist.gov/vuln/detail/CVE-2024-49380) )
---
--- Code snippet ( Golang ):
---
--- @
--- func postLocal(w http.ResponseWriter, r *http.Request) { ... }
--- @
---
--- See complete source example: [here](https://github.com/plentico/plenti/blob/01825e0dcd3505fac57adc2edf29f772d585c008/cmd/serve.go#L205)
---
--- __Writing a predicate with this fact and others__ ( motivation: [CVE-2024-49380](https://nvd.nist.gov/vuln/detail/CVE-2024-49380) )
---
--- @
--- looks_like_user_input( RequestParam ) :-
---     kb_param_has_resolved_type( RequestParam, \'net/http.Request\' ),
---     kb_param_has_resolved_type( ResponseParam, \'net/http.ResponseWriter\' ),
---     kb_param_i_of_callable( ResponseParam, 0, Handler ),
---     kb_param_i_of_callable( RequestParam, 1, Handler ).
--- @
---
--- Other facts combined in this predicate:
---
---     * 'ParamiOfCallable'
---
-data ParamResolvedType = ParamResolvedType
-    Param -- ^
-    ResolvedType -- ^
-    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
--- |
---
--- __Name__
---
--- This is how the fact will look inside the Prolog file
---
--- @
--- kb_class_def( Class, Name, DefinedInFile ).
--- @
---
--- __When should I use this fact__ ( motivation: [CVE-2024-53995](https://nvd.nist.gov/vuln/detail/CVE-2024-53995) )
---
--- @
--- # authentication.py
--- class LoginHandler(BaseHandler): ...
---
--- # index.py
--- from tornado.web import RequestHandler
--- class BaseHandler(RequestHandler): ...
--- @
---
--- See complete source example [here](https://github.com/SickChill/sickchill/blob/846adafdfab579281353ea08a27bbb813f9a9872/sickchill/views/authentication.py#L10),
--- [here](https://github.com/SickChill/sickchill/blob/846adafdfab579281353ea08a27bbb813f9a9872/sickchill/views/index.py#L35)
--- and [here](https://github.com/SickChill/sickchill/blob/846adafdfab579281353ea08a27bbb813f9a9872/sickchill/views/index.py#L15)
---
--- __Writing a predicate with this fact and others__ ( motivation: [CVE-2024-53995](https://nvd.nist.gov/vuln/detail/CVE-2024-53995) )
---
--- @
--- skip_level_subclass_of( Subclass, \'tornado.web.RequestHandler\' ) :-
---     kb_class_def( Subclass, _, _ ),
---     kb_class_has_1st_party_super( Subclass, ClassName, ClassDefinedInFile ),
---     kb_class_def( Class, ClassName, ClassDefinedInFile )
---     kb_class_has_3rd_party_super( Class, _, \'tornado.web.RequestHandler\' ).
--- @
---
--- Other facts combined in this predicate:
---
---     * 'ClassHas1stPartySuper'
---     * 'ClassHas3rdPartySuper'
---
-data ClassDef = ClassDef
-    Class -- ^
-    Token.ClassName -- ^
-    ClassDefinedInFile -- ^
-    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
--- |
---
--- __Name__
---
--- This is how the fact will look inside the Prolog file
---
--- @
--- kb_func_def( Func, Name, DefinedInFile, DefinedInDir ).
--- @
---
--- __When should I use this fact__ ( motivation: [CVE-2024-29028](https://nvd.nist.gov/vuln/detail/CVE-2024-29028) )
---
--- @
--- # http_getter.go
--- g.GET("/get/httpmeta", func(c echo.Context) error {
---     urlStr := c.QueryParam("url")
---     ...
---     getter.GetHTMLMeta(urlStr)
---
--- # html_meta.go
--- func GetHTMLMeta(urlStr string) (*HTMLMeta, error) {
---     ...
---     http.Get(urlStr)
--- @
---
--- See complete source example [here](https://github.com/usememos/memos/blob/v0.14.0/api/v1/http_getter.go#L23),
--- and [here](https://github.com/usememos/memos/blob/v0.14.0/plugin/http-getter/html_meta.go#L24)
---
--- __Writing a predicate with this fact and others__ ( motivation: [CVE-2024-29028](https://nvd.nist.gov/vuln/detail/CVE-2024-29028) )
---
--- @
--- suspected_ssrf_sink( Func ) :-
---     kb_resolved_call( Call, \'net/http.Get\' ),
---     kb_arg_i_for_call( Arg, 0, Call ),
---     utils_dataflow_path( Param, Arg ),
---     kb_param_has_resolved_type( Param, \'string\' ),
---     kb_param_i_of_callable( Param, _, Func ),
---     kb_func_def( Func, Name, _, FuncDefinedInDir ),
---     kb_call_1st_party_func_defined_in_dir( _, Name, FuncDefinedInDir ).
--- @
---
--- Other facts combined in this predicate:
---
---     * 'CallResolved'
---     * 'ArgiForCall'
---     * 'ParamResolvedType'
---     * 'ParamiOfCallable'
---     * 'Call1stPartyFuncDefinedInDir'
---
-data FuncDef = FuncDef
-    Func -- ^
-    Token.FuncName -- ^
-    FuncDefinedInFile -- ^
-    FuncDefinedInDir -- ^
-    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
--- |
---
--- __Name__
---
--- This is how the fact will look inside the Prolog file
---
--- @
--- kb_call_1st_party_func_defined_in_dir( Call, Name, DefinedInDir ).
--- @
---
--- __When should I use this fact__ ( motivation: [CVE-2024-29028](https://nvd.nist.gov/vuln/detail/CVE-2024-29028) )
---
--- @
--- # http_getter.go
--- g.GET("/get/httpmeta", func(c echo.Context) error {
---     urlStr := c.QueryParam("url")
---     ...
---     getter.GetHTMLMeta(urlStr)
---
--- # html_meta.go
--- func GetHTMLMeta(urlStr string) (*HTMLMeta, error) {
---     ...
---     http.Get(urlStr)
--- @
---
--- See complete source example [here](https://github.com/usememos/memos/blob/v0.14.0/api/v1/http_getter.go#L23),
--- and [here](https://github.com/usememos/memos/blob/v0.14.0/plugin/http-getter/html_meta.go#L24)
---
--- __Writing a predicate with this fact and others__ ( motivation: [CVE-2024-29028](https://nvd.nist.gov/vuln/detail/CVE-2024-29028) )
---
--- @
--- suspected_ssrf_sink( Func ) :-
---     kb_resolved_call( Call, \'net/http.Get\' ),
---     kb_arg_i_for_call( Arg, 0, Call ),
---     utils_dataflow_path( Param, Arg ),
---     kb_param_has_resolved_type( Param, \'string\' ),
---     kb_param_i_of_callable( Param, _, Func ),
---     kb_func_def( Func, Name, _, FuncDefinedInDir ),
---     kb_call_1st_party_func_from_dir( _, Name, FuncDefinedInDir ).
--- @
---
--- Other facts combined in this predicate:
---
---     * 'CallResolved'
---     * 'ArgiForCall'
---     * 'ParamResolvedType'
---     * 'ParamiOfCallable'
---
-data Call1stPartyFuncDefinedInDir = Call1stPartyFuncDefinedInDir
-    Call -- ^
-    FuncName -- ^
-    FuncDefinedInDir -- ^
-    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data Call1stPartyFuncDefinedInFile = Call1stPartyFuncDefinedInFile
-    Call -- ^
-    FuncName -- ^
-    FuncDefinedInFile -- ^
-    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data AssignValueToToplevelVarName = AssignValueToToplevelVarName
-    AssignedValue -- ^
-    Token.VarName -- ^
-    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
--- |
---
--- __Description:__
---
--- Input parameter of some callable ( method, function, lambda ) has the specified name
---
--- __Prolog signature:__
---
--- @
--- kb_param_has_name( Param, Name ).
--- @
---
--- __Code Example ( Javascript ):__
---
--- Motivated by [GHSL-2023-203](https://github.com/advplyr/audiobookshelf/security/advisories/GHSA-mgj7-rfx8-vhpr#event-116560)
--- ( [source code](https://github.com/advplyr/audiobookshelf/blob/d7b2476473ef1934eedec41425837cddf2d4b13e/server/controllers/AuthorController.js#L66)
--- and see also [here](https://github.com/advplyr/audiobookshelf/blob/d7b2476473ef1934eedec41425837cddf2d4b13e/server/controllers/AuthorController.js#L74)
--- and [here](https://github.com/advplyr/audiobookshelf/blob/d7b2476473ef1934eedec41425837cddf2d4b13e/server/routers/ApiRouter.js#L201) )
---
--- @
--- // ApiRouter.js
--- const express = require(\'express\')
---
--- class ApiRouter {
---   constructor(Server) { this.router = express() }
---   init() { this.router.patch(\'\/authors\/:id', ... , AuthorController.update.bind(this)) }
---
--- // AuthorController.js
--- class AuthorController { async update(req, res) { ... } }
--- @
---
--- __Writing new predicates:__
---
--- Facts combined in this predicate:
---
---     * 'ParamName'
---     * 'ParamiOfCallable'
---
--- @
--- http_request_param_of_method( Param, Method ) :-
---     kb_param_name( Param, \'req\' ),
---     kb_param_name( SecondParam, \'res\' ),
---     kb_param_i_of_callable( Param, 0, Method ),
---     kb_param_i_of_callable( SecondParam, 1, Method ).
--- @
---
--- Facts combined in this predicate:
---
---     * 'ArgiForCall'
---     * 'ClassName'
---     * 'MethodName'
---
--- @
--- request_handler( Method ) :-
---     kb_resolved_call( Call, \'express.patch\' ),
---     kb_arg_i_for_call( RequestHandler, 2, Call ),
---     kb_resolved_part_i_call( RequestHandler, 0, ClassName ),
---     kb_resolved_part_i_call( RequestHandler, 1, MethodName ),
---     kb_method_of_class( Method, Class ),
---     kb_method_name( Method, MethodName ),
---     kb_class_name( Class, ClassName ).
--- @
---
---
-data ParamName = ParamName
-    Param -- ^
-    Token.ParamName -- ^
-    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
--- |
---
--- __Name__
---
--- This is how the fact will look inside the Prolog file
---
--- @
--- kb_class_has_1st_party_super( Class, SuperName, SuperDefinedInFile ).
--- @
---
--- __When should I use this fact__ ( motivation: [CVE-2024-53995](https://nvd.nist.gov/vuln/detail/CVE-2024-53995) )
---
--- @
--- # authentication.py
--- class LoginHandler(BaseHandler): ...
---
--- # index.py
--- from tornado.web import RequestHandler
--- class BaseHandler(RequestHandler): ...
--- @
---
--- See complete source example [here](https://github.com/SickChill/sickchill/blob/846adafdfab579281353ea08a27bbb813f9a9872/sickchill/views/authentication.py#L10),
--- [here](https://github.com/SickChill/sickchill/blob/846adafdfab579281353ea08a27bbb813f9a9872/sickchill/views/index.py#L35)
--- and [here](https://github.com/SickChill/sickchill/blob/846adafdfab579281353ea08a27bbb813f9a9872/sickchill/views/index.py#L15)
---
--- __Writing a predicate with this fact and others__ ( motivation: [CVE-2024-53995](https://nvd.nist.gov/vuln/detail/CVE-2024-53995) )
---
--- @
--- skip_level_subclass_of( Subclass, \'tornado.web.RequestHandler\' ) :-
---     kb_class_def( Subclass, _, _ ),
---     kb_class_has_1st_party_super( Subclass, ClassName, ClassDefinedInFile ),
---     kb_class_def( Class, ClassName, ClassDefinedInFile )
---     kb_class_has_3rd_party_super( Class, _, \'tornado.web.RequestHandler\' ).
--- @
---
--- Other facts combined in this predicate:
---
---     * 'ClassDef'
---     * 'ClassHas3rdPartySuper'
---
-data ClassHas1stPartySuper = ClassHas1stPartySuper
-    Class -- ^
-    Token.SuperName -- ^
-    SuperDefinedInFile -- ^
-    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
--- |
---
--- __Name__
---
--- This is how the fact will look inside the Prolog file
---
--- @
--- kb_class_has_3rd_party_super( Class, SuperName, SuperQualifiedName ).
--- @
---
--- __When should I use this fact__ ( motivation: [CVE-2024-53995](https://nvd.nist.gov/vuln/detail/CVE-2024-53995) )
---
--- @
--- # authentication.py
--- class LoginHandler(BaseHandler): ...
---
--- # index.py
--- from tornado.web import RequestHandler
--- class BaseHandler(RequestHandler): ...
--- @
---
--- See complete source example [here](https://github.com/SickChill/sickchill/blob/846adafdfab579281353ea08a27bbb813f9a9872/sickchill/views/authentication.py#L10),
--- [here](https://github.com/SickChill/sickchill/blob/846adafdfab579281353ea08a27bbb813f9a9872/sickchill/views/index.py#L35)
--- and [here](https://github.com/SickChill/sickchill/blob/846adafdfab579281353ea08a27bbb813f9a9872/sickchill/views/index.py#L15)
---
--- __Writing a predicate with this fact and others__ ( motivation: [CVE-2024-53995](https://nvd.nist.gov/vuln/detail/CVE-2024-53995) )
---
--- @
--- skip_level_subclass_of( Subclass, \'tornado.web.RequestHandler\' ) :-
---     kb_class_def( Subclass, _, _ ),
---     kb_class_has_1st_party_super( Subclass, ClassName, ClassDefinedInFile ),
---     kb_class_def( Class, ClassName, ClassDefinedInFile )
---     kb_class_has_3rd_party_super( Class, _, \'tornado.web.RequestHandler\' ).
--- @
---
--- Other facts combined in this predicate:
---
---     * 'ClassDef'
---     * 'ClassHas1stPartySuper'
---
-data ClassHas3rdPartySuper = ClassHas3rdPartySuper
-    Class -- ^
-    Token.SuperName -- ^
-    SuperQualifiedName -- ^
-    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
--- |
---
--- __Name__
---
--- This is how the fact will look inside the Prolog file
---
--- @
--- kb_call_method_of_class( Call, Method, Class ).
--- @
---
--- __When should I use this fact__ ( motivation: [CVE-2024-53995](https://nvd.nist.gov/vuln/detail/CVE-2024-53995) )
---
--- @
--- # index.py
--- from tornado.web import RequestHandler
--- class BaseHandler(RequestHandler): ...
---
--- # authentication.py
--- class LoginHandler(BaseHandler):
---     def post(self, ...):
---         n = self.get_query_argument("next", ...)
---         self.redirect(n or ...)
--- @
---
--- See complete source example [here](https://github.com/SickChill/sickchill/blob/846adafdfab579281353ea08a27bbb813f9a9872/sickchill/views/authentication.py#L10),
--- [here](https://github.com/SickChill/sickchill/blob/846adafdfab579281353ea08a27bbb813f9a9872/sickchill/views/index.py#L35)
--- and [here](https://github.com/SickChill/sickchill/blob/846adafdfab579281353ea08a27bbb813f9a9872/sickchill/views/index.py#L15)
---
--- __Writing a predicate with this fact and others__ ( motivation: [CVE-2024-53995](https://nvd.nist.gov/vuln/detail/CVE-2024-53995) )
---
--- @
--- user_controlled_query_argument( Call ) :-
---     kb_call_method_of_class( Call, \'get_query_argument\', Class ),
---     kb_class_has_3rd_party_super( Class, \'tornado.web.RequestHandler\'),
---     kb_arg_i_for_call( QueryParamName, 0, Call),
---     kb_const_string( QueryParamName, _ ).
--- @
---
--- Other facts combined in this predicate:
---
---     * 'ClassHas3rdPartySuper'
---     * 'ArgiForCall'
---     * 'ConstString'
---
-data CallMethodOfClass = CallMethodOfClass
-    Call -- ^
-    MethodName -- ^
-    Class -- ^
-    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
--- |
---
--- __Name__
---
--- This is how the fact will look inside the Prolog file
---
--- @
--- kb_call_method_of_untyped_named_param( Param, ParamName, MethodName ).
--- @
---
--- __When should I use this fact__ ( motivation: [CVE-2024-47769](https://nvd.nist.gov/vuln/detail/CVE-2024-47769) )
---
--- @
--- // corePublicRouter.js
--- const express = require('express');
--- const router = express.Router();
---
--- router.route('...').get(function (req, res) {
---     const { ..., file } = req.params;
---     const fileName = file;
---     return res.sendFile(fileName, ...);
--- }
--- @
---
--- See complete source example [here](https://github.com/idurar/idurar-erp-crm/blob/d7b2215a17bb2b52acfdab8f1646685d13df9a00/backend/src/routes/coreRoutes/corePublicRouter.js#L8-L24),
---
--- __Writing a predicate with this fact and others__ ( motivation: [CVE-2024-47769](https://nvd.nist.gov/vuln/detail/CVE-2024-47769) )
---
--- @
--- arbitrary_file_read( Call ) :-
---     kb_call_resolved( Call, \'express.Router.route.get\'),
---     kb_call_method_of_untyped_named_param( Param, \'res\', \'sendFile\' ),
---     kb_arg_i_for_call( Lambda, 0, Call ),
---     kb_param_i_of_callable( Param, 1, Lambda ).
--- @
---
--- Other facts combined in this predicate:
---
---     * 'CallResolved'
---     * 'ArgiForCall'
---     * 'ParamiOfCallable'
---
-data CallMethodOfUntypedNamedParam = CallMethodOfUntypedNamedParam
-    Call -- ^
-    MethodName -- ^
-    Token.ParamName -- ^
-    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
--- |
--- capture inheritance from third party classes
-data ClassAnnotation = ClassAnnotation
-    Class -- ^
-    Annotation -- ^
-    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data CallableAnnotation = CallableAnnotation
-    Callable -- ^
-    Annotation -- ^
-    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
--- |
---
--- __Name__
---
--- This is how the fact will look inside the Prolog file
---
--- @
--- kb_callable_source_body_length( Callable, N ).
--- @
---
--- Number of source-level @[ Ast.Stmt ]@ statements in the callable's body,
--- as observed at codegen time (before any lowering to bitcode). Independent
--- of how many bitcode instructions the body lowered to.
---
--- Intended for query predicates that need a source-fidelity signal ( e.g.
--- \"this wrapper's source body is a single statement\" for HOC-unwrap ),
--- rather than trying to reconstruct that shape from flat SSA bitcode after
--- the fact.
---
--- Emitted for 'Method', 'Lambda' and 'Function' callables. Not emitted for
--- 'Script' \-- see 'Callable.numOriginalSourceInstructions'.
-data CallableSourceBodyLength = CallableSourceBodyLength
-    Callable -- ^
-    Word -- ^ number of source-level statements in the body
-    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
--- |
--- capture usage of inherited third party methods
-data MethodOfClass = MethodOfClass
-    Method -- ^
-    Class -- ^
-    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
--- |
---
--- __Name__
---
--- This is how the fact will look inside the Prolog file
---
--- @
--- kb_arg_i_for_call( Arg, Index, Call ).
--- @
---
--- __When should I use this fact__ ( motivation: [CVE-2024-47769](https://nvd.nist.gov/vuln/detail/CVE-2024-47769) )
---
--- @
--- // corePublicRouter.js
--- const express = require('express');
--- const router = express.Router();
---
--- router.route('...').get(function (req, res) {
---     const { ..., file } = req.params;
---     const fileName = file;
---     return res.sendFile(fileName, ...);
--- }
--- @
---
--- See complete source example [here](https://github.com/idurar/idurar-erp-crm/blob/d7b2215a17bb2b52acfdab8f1646685d13df9a00/backend/src/routes/coreRoutes/corePublicRouter.js#L8-L24),
---
--- __Writing a predicate with this fact and others__ ( motivation: [CVE-2024-47769](https://nvd.nist.gov/vuln/detail/CVE-2024-47769) )
---
--- @
--- arbitrary_file_read( Call ) :-
---     kb_call_resolved( Call, \'express.Router.route.get\'),
---     kb_call_method_of_untyped_named_param( Param, \'res\', \'sendFile\' ),
---     kb_arg_i_for_call( Lambda, 0, Call ),
---     kb_param_i_of_callable( Param, 1, Lambda ).
--- @
---
--- Other facts combined in this predicate:
---
---     * 'CallResolved'
---     * 'CallMethodOfUntypedNamedParam'
---     * 'ParamiOfCallable'
---
--- ==== __Tip 💡__
---
--- When the exact index is irrelevant, use:
---
--- @
--- kb_arg_i_for_call( Arg, _, Call ).
--- @
---
-data ArgiForCall = ArgiForCall
-    Arg -- ^
-    ArgIndex -- ^
-    Call -- ^
-    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
--- |
---
--- __Name__
---
--- This is how the fact will look inside the Prolog file
---
--- @
--- kb_param_i_of_callable( Param, Index, Callable ).
--- @
---
--- __When should I use this fact__ ( motivation: [CVE-2024-29028](https://nvd.nist.gov/vuln/detail/CVE-2024-29028) )
---
--- @
--- # http_getter.go
--- g.GET("/get/httpmeta", func(c echo.Context) error {
---     urlStr := c.QueryParam("url")
---     ...
---     getter.GetHTMLMeta(urlStr)
---
--- # html_meta.go
--- func GetHTMLMeta(urlStr string) (*HTMLMeta, error) {
---     ...
---     http.Get(urlStr)
--- @
---
--- See complete source example [here](https://github.com/usememos/memos/blob/v0.14.0/api/v1/http_getter.go#L23),
--- and [here](https://github.com/usememos/memos/blob/v0.14.0/plugin/http-getter/html_meta.go#L24)
---
--- __Writing a predicate with this fact and others__ ( motivation: [CVE-2024-29028](https://nvd.nist.gov/vuln/detail/CVE-2024-29028) )
---
--- @
--- suspected_ssrf_sink( Func ) :-
---     kb_resolved_call( Call, \'net/http.Get\' ),
---     kb_arg_i_for_call( Arg, 0, Call ),
---     utils_dataflow_path( Param, Arg ),
---     kb_param_has_resolved_type( Param, \'string\' ),
---     kb_param_i_of_callable( Param, _, Func ),
---     kb_func_def( Func, Name, _, FuncDefinedInDir ),
---     kb_call_1st_party_func_defined_in_dir( _, Name, FuncDefinedInDir ).
--- @
---
--- Other facts combined in this predicate:
---
---     * 'CallResolved'
---     * 'ArgiForCall'
---     * 'ParamResolvedType'
---     * 'FuncDef'
---     * 'Call1stPartyFuncDefinedInDir'
---
--- ==== __Tip 💡__
---
--- When the _exact index_ is _irrelevant_, use:
---
--- @
--- kb_param_i_of_callable( Param, _, Callable ).
--- @
---
-data ParamiOfCallable = ParamiOfCallable
-    Param -- ^
-    ParamIndex -- ^ 0-based
-    Callable -- ^
-    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data CallResolved = CallResolved
-    Call -- ^
-    Resolved -- ^
-    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
--- |
---
--- __Name__
---
--- This is how the fact will look inside the Prolog file
---
--- @
--- kb_called_from( Call, Callable ).
--- @
---
--- __When should I use this fact__
---
--- Web-app request handlers routinely /extract fields/ from the incoming
--- request \- headers, cookies, query parameters, body \- and the /name/
--- of the field is often the security-relevant piece ( e.g. the constant
--- string \'x-api-key\' says "this callable does API-key authentication" ).
--- To reason about /which/ callable extracts /which/ field, you need to
--- know that a particular call site lives inside the body of a particular
--- callable.
---
--- No pre-existing fact tied a 'Call' back to its enclosing 'Callable' \-
--- 'ParamiOfCallable' does the analogous thing for /parameters/ only.
--- Because 'CalledFrom' exposes the 'Call' /location/ ( not just its FQN ),
--- it composes with 'ArgiForCall' and 'ConstString' to also surface the
--- /arguments/ passed at that specific call site.
---
--- Code snippet ( Typescript, Next.js \- formbricks at v3.16.0 ):
---
--- @
--- export const authenticateRequest = async (request: Request) => {
---     const apiKey = request.headers.get(\"x-api-key\");
---     if (!apiKey) return null;
---     const apiKeyData = await getApiKeyWithPermissions(apiKey);
---     ...
--- };
--- @
---
--- See complete source example [here](https://github.com/formbricks/formbricks/blob/v3.16.0/apps/web/app/api/v1/auth.ts#L7-L36)
---
--- __Writing a predicate with this fact and others__
---
--- Compose 'CalledFrom' with 'ArgiForCall' and 'ConstString' to enumerate
--- the constant-string header names each callable extracts from the
--- incoming request:
---
--- @
--- extracts_request_header_named( Callable, HeaderName ) :-
---     kb_called_from( Call, Callable ),
---     kb_call_resolved( Call, \'Request.headers.get\' ),
---     kb_arg_i_for_call( HeaderConst, 0, Call ),
---     kb_const_string( HeaderConst, HeaderName ).
--- @
---
--- Applied to @authenticateRequest@ above, this yields
--- @extracts_request_header_named( authenticateRequest, \'x-api-key\' )@ \-
--- one of the six structural indicators for recognizing Shape-A
--- ( identity-carrier ) request authenticators.
---
--- Other facts combined in this predicate:
---
---     * 'CallResolved'
---     * 'ArgiForCall'
---     * 'ConstString'
---
-data CalledFrom = CalledFrom
-    Call -- ^
-    Callable -- ^
-    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-
--- |
---
--- Usage:
---
--- @
--- kb_const_str( Param, Index, Callable ).
--- @
---
--- ==== __Tip 💡__
---
--- sometimes the exact index is irrelevant, see 'Arg_for_Call'
---
-data ConstString = ConstString
-    ConstStr -- ^
-    Token.ConstStr -- ^
-    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
--- |
---
--- __Name__
---
--- This is how the fact will look inside the Prolog file
---
--- @
--- kb_const_int( Loc, Value ).
--- @
---
--- __When should I use this fact__
---
--- Any time a query needs to discriminate on the /value/ of a constant
--- integer literal appearing in source code, typically as an argument
--- to a function that carries semantic information in that integer.
--- The canonical example is the HTTP status code passed to a response
--- constructor:
---
--- @
--- return Response.json({ error: \"unauthorized\" }, { status: 401 });
--- @
---
--- Recognizing this shape ( a bad status code returned early from a
--- callable ) is used to identify authenticating functions.
---
--- __Writing a predicate with this fact and others__
---
--- @
--- utils_ts_response_json_with_status( Function, Code ) :-
---     kb_call_resolved( OuterCall, \'nodejs.Response.json\' ),
---     kb_arg_i_for_call( DictifyCall, 1, OuterCall ),
---     kb_arg_i_for_call( KvCall, _, DictifyCall ),
---     kb_arg_i_for_call( KeyLoc, 0, KvCall ),
---     kb_const_string( KeyLoc, \'status\' ),
---     kb_arg_i_for_call( ValueLoc, 1, KvCall ),
---     kb_const_int( ValueLoc, Code ),
---     kb_called_from( OuterCall, Function ).
--- @
---
--- Other facts combined in this example predicate:
---
---     * 'CallResolved'
---     * 'ArgiForCall'
---     * 'ConstString'
---     * 'CalledFrom'
---
-data ConstInteger = ConstInteger
-    ConstInt -- ^
-    Token.ConstInt -- ^
-    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
--- |
---
--- __Name__
---
--- This is how the fact will look inside the Prolog file
---
--- @
--- kb_const_null( Loc ).
--- @
---
--- __When should I use this fact__
---
--- Returning early from a function with a null value has many uses cases related to security.
--- ( Python @None@ and Ruby @nil@ use this predicate as well )
---
--- __Writing a predicate with this fact and others__
---
--- @
--- kb_gated_return_null( Cond ) :-
---     kb_gated_return( Cond, ReturnedValue ),
---     kb_const_null( ReturnedValue ).
--- @
---
--- Other facts combined in this example predicate:
---
---     * 'GatedReturn'
---
-data ConstNull = ConstNull Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
--- |
---
--- __Name__
---
--- This is how the fact will look inside the Prolog file
---
--- @
--- kb_gated_return( Cond, ReturnedValue ).
--- @
---
--- __When should I use this fact__
---
--- Authenticating functions reject invalid credentials with an early return
--- from a guarded @if@. This fact pinpoints that rejection gate.
---
--- __Writing a predicate with this fact and others__
---
--- @
--- utils_early_return_null_on_missing_request_header_value( Callable, KeyName ) :-
---     kb_called_from( Call, Callable ),
---     kb_call_resolved( Call, \'nodejs.Request.headers.get\' ),
---     kb_arg_i_for_call( KeyArg, 0, Call ),
---     kb_const_string( KeyArg, KeyName ),
---     utils_intra_dataflow_path( Call, Var, _ ),
---     kb_gated_return_null( Cond ),
---     utils_intra_dataflow_path( Var, Cond, _ ).
---
--- kb_gated_return_null( Cond ) :- kb_gated_return( Cond, RV ), kb_const_null( RV ).
--- @
---
--- Other facts combined in this example predicate:
---
---     * 'ConstNull'
---     * 'CallResolved'
---     * 'ArgiForCall'
---     * 'ConstString'
---     * 'CalledFrom'
---
-data GatedReturn = GatedReturn
-    Cond -- ^
-    ReturnedValue -- ^
-    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
--- |
---
--- __Name__
---
--- This is how the fact will look inside the Prolog file
---
--- @
--- kb_comparison( Cond, Lhs, Rhs, Op ).
--- @
---
--- __When should I use this fact__
---
--- Binary comparison instructions ( currently @==@ \/ @===@ mapped to
--- the Prolog atom @eq@, and @!=@ \/ @!==@ mapped to @neq@ ) fire this
--- fact. The @Cond@ slot is the location of the comparison\'s output
--- variable, which makes composing with 'GatedReturn' straightforward:
--- when the boolean condition of an @if@ that early-returns is itself a
--- comparison, both facts share the same location in the @Cond@ slot.
---
--- __Writing a predicate with this fact and others__
---
--- @
--- gated_return_on_comparison( Lhs, Rhs, Op, ReturnedValue ) :-
---     kb_gated_return( Cond, ReturnedValue ),
---     kb_comparison( Cond, Lhs, Rhs, Op ).
--- @
---
--- Other facts combined in this example predicate:
---
---     * 'GatedReturn'
---
-data Comparison = Comparison
-    Cond -- ^
-    Lhs -- ^
-    Rhs -- ^
-    ComparisonOp -- ^
-    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
--- |
---
--- __Name__
---
--- This is how the fact will look inside the Prolog file
---
--- @
--- kb_callable_returns_value( Callable, ReturnedValue ).
--- @
---
--- __When should I use this fact__
---
--- Every explicit `return exp;` inside a callable's body fires this fact
--- once, keyed by the enclosing callable and the returned expression's
--- location. Downstream predicates like `kb_const_null` or
--- `kb_call_resolved` add semantic meaning to the value slot.
---
-data CallableReturnsValue = CallableReturnsValue
-    Callable -- ^
-    ReturnedValue -- ^
-    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
--- |
---
--- __Name__
---
--- This is how the fact will look inside the Prolog file
---
--- @
--- kb_callable_returns_without_value( Callable, ReturnStmtLocation ).
--- @
---
--- __When should I use this fact__
---
--- User-written bare `return;` (no value expression) fires this fact once,
--- keyed by the enclosing callable and the location of the return
--- statement itself. Distinct fact from 'CallableReturnsValue' because
--- there is no value-expression location to anchor on; the return
--- statement location is used instead.
---
-data CallableReturnsWithoutValue = CallableReturnsWithoutValue
-    Callable -- ^
-    Location -- ^
-    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
--- |
---
--- __Name__
---
--- This is how the fact will look inside the Prolog file
---
--- @
--- kb_dataflow_edge( From, To ).
--- @
---
-data DataflowEdge = DataflowEdge
-    From -- ^
-    To -- ^
-    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data Arg = Arg Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-data Call = Call Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-data Param = Param Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-data Class = Class Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data To = To Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-data From = From Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-data Func = Func Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-data Method = Method Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-data Callable = Callable Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-data ConstStr = ConstStr Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-data ConstInt = ConstInt Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-data Annotation = Annotation Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-data AssignedValue = AssignedValue Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-data ConstBoolTrue = ConstBoolTrue Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-data Cond = Cond Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-data Lhs = Lhs Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-data Rhs = Rhs Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-data ComparisonOp = ComparisonOp String deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-data ReturnedValue = ReturnedValue Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data Keyword = Keyword String deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-data Resolved = Resolved Fqn.Fqn deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-data ArgIndex = ArgIndex Word deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-data ParamIndex = ParamIndex Word deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-data FuncName = FuncName String deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-data MethodName = MethodName String deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-data ConstStrValue = ConstStrValue String deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-data SuperQualifiedName = SuperQualifiedName Fqn.Fqn deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data FuncDefinedInDir = FuncDefinedInDir FilePath deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-data FuncDefinedInFile = FuncDefinedInFile FilePath deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-data ClassDefinedInFile = ClassDefinedInFile FilePath deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-data SuperDefinedInFile = SuperDefinedInFile FilePath deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
--- |
-data ResolvedType = ResolvedType
-    Fqn.Fqn -- ^
-    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
-data ResolvedSuper = ResolvedSuper Fqn.Fqn deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
--- |
--- * each fact is derived from a /single/ bitcode 'Bitcode.Instruction'
---
--- * often, a single bitcode instruction will yield /more/ than one fact
---
-data Fact
-   = FuncDefCtor FuncDef 
-   | ClassDefCtor ClassDef
-   | ParamNameCtor ParamName
-   | ArgiForCallCtor ArgiForCall
-   | ConstStringCtor ConstString
-   | ConstIntegerCtor ConstInteger
-   | DataflowEdgeCtor DataflowEdge
-   | CallResolvedCtor CallResolved
-   | CalledFromCtor CalledFrom
-   | ConstBoolTrueCtor ConstBoolTrue
-   | ConstNullCtor ConstNull
-   | GatedReturnCtor GatedReturn
-   | ComparisonCtor Comparison
-   | CallableReturnsValueCtor CallableReturnsValue
-   | CallableReturnsWithoutValueCtor CallableReturnsWithoutValue
-   | MethodOfClassCtor MethodOfClass
-   | ClassAnnotationCtor ClassAnnotation
-   | ParamiOfCallableCtor ParamiOfCallable
-   | KeywordArgForCallCtor KeywordArgForCall
-   | ParamResolvedTypeCtor ParamResolvedType
-   | CallMethodOfClassCtor CallMethodOfClass
-   | CallableAnnotationCtor CallableAnnotation
-   | ClassHas1stPartySuperCtor ClassHas1stPartySuper
-   | ClassHas3rdPartySuperCtor ClassHas3rdPartySuper
-   | CallableSourceBodyLengthCtor CallableSourceBodyLength
-   | AssignValueToToplevelVarNameCtor AssignValueToToplevelVarName
-   | Call1stPartyFuncDefinedInDirCtor Call1stPartyFuncDefinedInDir
-   | Call1stPartyFuncDefinedInFileCtor Call1stPartyFuncDefinedInFile
-   | CallMethodOfUntypedNamedParamCtor CallMethodOfUntypedNamedParam
-   deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
-
--- |
--- Translate a code fact into a prolog fact
---
--- 'ParamName'
---
--- @
--- kb_param_has_name( Param, Name ).
--- @
---
-prologify :: Fact -> String
-prologify (FuncDefCtor content) = prologify_FuncDef content
-prologify (ClassDefCtor content) = prologify_ClassDef content
-prologify (ParamNameCtor content) = prologify_ParamName content
-prologify (ArgiForCallCtor content) = prologifyArgiForCall content
-prologify (ConstStringCtor content) = prologify_ConstString content
-prologify (ConstIntegerCtor content) = prologify_ConstInteger content
-prologify (DataflowEdgeCtor content) = prologify_DataflowEdge content
-prologify (CallResolvedCtor content) = prologify_CallResolved content
-prologify (CalledFromCtor content) = prologify_CalledFrom content
-prologify (ConstBoolTrueCtor content) = prologify_ConstBoolTrue content
-prologify (ConstNullCtor content) = prologify_ConstNull content
-prologify (GatedReturnCtor content) = prologify_GatedReturn content
-prologify (ComparisonCtor content) = prologify_Comparison content
-prologify (CallableReturnsValueCtor content) = prologify_CallableReturnsValue content
-prologify (CallableReturnsWithoutValueCtor content) = prologify_CallableReturnsWithoutValue content
-prologify (MethodOfClassCtor content) = prologify_MethodOfClass content
-prologify (ClassAnnotationCtor content) = prologify_ClassAnnotation content
-prologify (ParamiOfCallableCtor content) = prologify_ParamiOfCallable content
-prologify (ParamResolvedTypeCtor content) = prologify_ParamResolvedType content
-prologify (CallMethodOfClassCtor content) = prologify_CallMethodOfClass content
-prologify (KeywordArgForCallCtor content) = prologify_KeywordArgForCall content
-prologify (CallableAnnotationCtor content) = prologify_CallableAnnotation content
-prologify (CallableSourceBodyLengthCtor content) = prologify_CallableSourceBodyLength content
-prologify (ClassHas1stPartySuperCtor content) = prologify_ClassHas1stPartySuper content
-prologify (ClassHas3rdPartySuperCtor content) = prologify_ClassHas3rdPartySuper content
-prologify (AssignValueToToplevelVarNameCtor content) = prologify_AssignValueToToplevelVarName content
-prologify (Call1stPartyFuncDefinedInDirCtor content) = prologify_Call1stPartyFuncDefinedInDir content
-prologify (Call1stPartyFuncDefinedInFileCtor content) = prologify_Call1stPartyFuncDefinedInFile content
-prologify (CallMethodOfUntypedNamedParamCtor content) = prologify_CallMethodOfUntypedNamedParam content
-
-prologify_ParamResolvedType' :: Location -> String -> String
-prologify_ParamResolvedType' l fqn = printf "kb_param_has_resolved_type( %s, \'%s\' )." (locationify l) fqn
-
-prologify_ParamResolvedType :: ParamResolvedType -> String
-prologify_ParamResolvedType (ParamResolvedType (Param loc) (ResolvedType fqn)) = prologify_ParamResolvedType' loc (prologifyFqn fqn)
-
-prologify_CallMethodOfClass' :: Location -> String -> Location -> String
-prologify_CallMethodOfClass' call method klass = printf "kb_call_method_of_class( %s, \'%s\', %s )." (locationify call) method (locationify klass)
-
-prologify_CallMethodOfClass :: CallMethodOfClass -> String
-prologify_CallMethodOfClass (CallMethodOfClass (Call loc) (MethodName m) (Class c)) = prologify_CallMethodOfClass' loc m c
-
-prologify_ParamName' :: Location -> String -> String
-prologify_ParamName' l name = printf "kb_param_has_name( %s, \'%s\' )." (locationify l) name
-
-prologify_ParamName :: ParamName -> String
-prologify_ParamName (ParamName (Param loc) (Token.ParamName (Token.Named name _))) = prologify_ParamName' loc name
-
-prologify_ClassDef' :: Location -> String -> FilePath -> String
-prologify_ClassDef' l name f = printf "kb_class_def( %s, \'%s\', \'%s\' )." (locationify l) name f
-
-prologify_ClassDef :: ClassDef -> String
-prologify_ClassDef (ClassDef (Class loc) (Token.ClassName (Token.Named name _)) (ClassDefinedInFile f)) = prologify_ClassDef' loc name f
-
-prologify_FuncDef' :: Location -> String -> FilePath -> FilePath -> String
-prologify_FuncDef' l name f d = printf "kb_func_def( %s, \'%s\', \'%s\', \'%s\' )." (locationify l) name f d
-
-prologify_FuncDef :: FuncDef -> String
-prologify_FuncDef (FuncDef (Func loc) (Token.FuncName (Token.Named name _)) (FuncDefinedInFile f) (FuncDefinedInDir d)) = prologify_FuncDef' loc name f d
-
-unquote :: String -> String
-unquote = filter (/= '\'')
-
-prologify_ConstString' :: Location -> String -> String
-prologify_ConstString' l value = printf "kb_const_string( %s, \'%s\' )." (locationify l) (unquote value)
-
-prologify_ConstString :: ConstString -> String
-prologify_ConstString (ConstString (ConstStr loc) (Token.ConstStr value _)) = prologify_ConstString' loc value
-
-prologify_ConstInteger' :: Location -> Int -> String
-prologify_ConstInteger' l value = printf "kb_const_int( %s, %d )." (locationify l) value
-
-prologify_ConstInteger :: ConstInteger -> String
-prologify_ConstInteger (ConstInteger (ConstInt loc) (Token.ConstInt value _)) = prologify_ConstInteger' loc value
-
-prologify_CallResolved'' :: Location -> String -> Token.ClassName -> String
-prologify_CallResolved'' call m c = printf "kb_call_method_of_class( %s, %s, %s )." (locationify call) m (locationify (Token.getClassNameLocation c))
-
-prologify_CallResolved' :: Location -> Fqn.Fqn -> String
-prologify_CallResolved' call (Fqn.CallMethodOfClass _ m c) = prologify_CallResolved'' call m c 
-prologify_CallResolved' call fqn = printf "kb_call_resolved( %s, \'%s\' )." (locationify call) (prologifyFqn fqn)
-
-prologify_DataflowEdge :: DataflowEdge -> String
-prologify_DataflowEdge (DataflowEdge (From u) (To v)) = prologify_DataflowEdge' u v
-
-prologify_DataflowEdge' :: Location -> Location -> String
-prologify_DataflowEdge' u v = printf "kb_dataflow_edge( %s, %s )." (locationify u) (locationify v)
-
-prologify_CallResolved :: CallResolved -> String
-prologify_CallResolved (CallResolved (Call call) (Resolved fqn)) = prologify_CallResolved' call fqn
-
-prologify_ConstBoolTrue' :: Location -> String
-prologify_ConstBoolTrue' trueValue = printf "kb_class_name( %s, \'%s\' )." (locationify trueValue)
-
-prologify_ConstBoolTrue :: ConstBoolTrue -> String
-prologify_ConstBoolTrue (ConstBoolTrue trueValue) = prologify_ConstBoolTrue' trueValue
-
-prologify_ConstNull' :: Location -> String
-prologify_ConstNull' l = printf "kb_const_null( %s )." (locationify l)
-
-prologify_ConstNull :: ConstNull -> String
-prologify_ConstNull (ConstNull loc) = prologify_ConstNull' loc
-
-prologify_GatedReturn' :: Location -> Location -> String
-prologify_GatedReturn' c v = printf "kb_gated_return( %s, %s )." (locationify c) (locationify v)
-
-prologify_GatedReturn :: GatedReturn -> String
-prologify_GatedReturn (GatedReturn (Cond c) (ReturnedValue v)) = prologify_GatedReturn' c v
-
-prologify_Comparison' :: Location -> Location -> Location -> String -> String
-prologify_Comparison' c l r op = printf "kb_comparison( %s, %s, %s, %s )." (locationify c) (locationify l) (locationify r) op
-
-prologify_Comparison :: Comparison -> String
-prologify_Comparison (Comparison (Cond c) (Lhs l) (Rhs r) (ComparisonOp op)) = prologify_Comparison' c l r op
-
-prologify_CallableReturnsValue' :: Location -> Location -> String
-prologify_CallableReturnsValue' c v = printf "kb_callable_returns_value( %s, %s )." (locationify c) (locationify v)
-
-prologify_CallableReturnsValue :: CallableReturnsValue -> String
-prologify_CallableReturnsValue (CallableReturnsValue (Callable c) (ReturnedValue v)) = prologify_CallableReturnsValue' c v
-
-prologify_CallableReturnsWithoutValue' :: Location -> Location -> String
-prologify_CallableReturnsWithoutValue' c s = printf "kb_callable_returns_without_value( %s, %s )." (locationify c) (locationify s)
-
-prologify_CallableReturnsWithoutValue :: CallableReturnsWithoutValue -> String
-prologify_CallableReturnsWithoutValue (CallableReturnsWithoutValue (Callable c) s) = prologify_CallableReturnsWithoutValue' c s
-
-prologify_MethodOfClass' :: Location -> Location -> String
-prologify_MethodOfClass' m c = printf "kb_method_of_class( %s, %s )." (locationify m) (locationify c)
-
-prologify_MethodOfClass :: MethodOfClass -> String
-prologify_MethodOfClass (MethodOfClass (Method m) (Class c)) = prologify_MethodOfClass' m c
-
-prologify_ClassHas1stPartySuper' :: Location -> String -> FilePath -> String
-prologify_ClassHas1stPartySuper' c s f = printf "kb_class_has_1st_party_super( %s, \'%s\', \'%s\' )." (locationify c) s f
- 
-prologify_ClassHas1stPartySuper :: ClassHas1stPartySuper -> String
-prologify_ClassHas1stPartySuper (ClassHas1stPartySuper (Class c) (Token.SuperName (Token.Named s _)) (SuperDefinedInFile f)) = prologify_ClassHas1stPartySuper' c s f
-
-prologify_ClassHas3rdPartySuper' :: Location -> String -> Fqn.Fqn -> String
-prologify_ClassHas3rdPartySuper' c s f = printf "kb_class_has_3rd_party_super( %s, \'%s\', \'%s\' )." (locationify c) s (prologifyFqn f)
- 
-prologify_ClassHas3rdPartySuper :: ClassHas3rdPartySuper -> String
-prologify_ClassHas3rdPartySuper (ClassHas3rdPartySuper (Class c) (Token.SuperName (Token.Named s _)) (SuperQualifiedName f)) = prologify_ClassHas3rdPartySuper' c s f
-
-prologify_AssignValueToToplevelVarName :: AssignValueToToplevelVarName -> String
-prologify_AssignValueToToplevelVarName (AssignValueToToplevelVarName value varname) = prologify_AssignValueToToplevelVarName' value varname
-
-prologify_AssignValueToToplevelVarName' :: AssignedValue -> Token.VarName -> String
-prologify_AssignValueToToplevelVarName' (AssignedValue value) (Token.VarName (Token.Named varname l)) = prologify_AssignValueToToplevelVarName'' value varname (Location.filename l)
-
-prologify_AssignValueToToplevelVarName'' :: Location -> String -> FilePath -> String
-prologify_AssignValueToToplevelVarName'' value varname f = printf "kb_assign_value_to_toplevel_varname( %s, \'%s\', \'%s\', \'%s\')." (locationify value) varname f (takeDirectory f)
-
-prologify_Call1stPartyFuncDefinedInFile :: Call1stPartyFuncDefinedInFile -> String
-prologify_Call1stPartyFuncDefinedInFile (Call1stPartyFuncDefinedInFile call func f) = prologify_Call1stPartyFuncDefinedInFile' call func f
-
-prologify_Call1stPartyFuncDefinedInFile' :: Call -> FuncName -> FuncDefinedInFile -> String
-prologify_Call1stPartyFuncDefinedInFile' (Call call) (FuncName func) (FuncDefinedInFile f) = prologify_Call1stPartyFuncDefinedInFile'' call func f
-
-prologify_Call1stPartyFuncDefinedInFile'' :: Location -> String -> FilePath -> String
-prologify_Call1stPartyFuncDefinedInFile'' call func f = printf "kb_call_1st_party_func_defined_in_file( %s, \'%s\', \'%s\' )." (locationify call) func f
-
-prologify_Call1stPartyFuncDefinedInDir :: Call1stPartyFuncDefinedInDir -> String
-prologify_Call1stPartyFuncDefinedInDir (Call1stPartyFuncDefinedInDir call func d) = prologify_Call1stPartyFuncDefinedInDir' call func d
-
-prologify_Call1stPartyFuncDefinedInDir' :: Call -> FuncName -> FuncDefinedInDir -> String
-prologify_Call1stPartyFuncDefinedInDir' (Call call) (FuncName f) (FuncDefinedInDir d) = prologify_Call1stPartyFuncDefinedInDir'' call f d
-
-prologify_Call1stPartyFuncDefinedInDir'' :: Location -> String -> FilePath -> String
-prologify_Call1stPartyFuncDefinedInDir'' call f d = printf "kb_call_1st_party_func_defined_in_dir( %s, \'%s\', \'%s\' )." (locationify call) f d
-
-prologify_CallMethodOfUntypedNamedParam :: CallMethodOfUntypedNamedParam -> String
-prologify_CallMethodOfUntypedNamedParam (CallMethodOfUntypedNamedParam call method p) = prologify_CallMethodOfUntypedNamedParam' call method p
-
-prologify_CallMethodOfUntypedNamedParam' :: Call -> MethodName -> Token.ParamName -> String
-prologify_CallMethodOfUntypedNamedParam' (Call call) (MethodName m) (Token.ParamName (Token.Named _ p)) = prologify_CallMethodOfUntypedNamedParam'' call m p
-
-prologify_CallMethodOfUntypedNamedParam'' :: Location -> String -> Location -> String
-prologify_CallMethodOfUntypedNamedParam'' call m p = printf "kb_call_method_of_untyped_named_param( %s, \'%s\', %s )." (locationify call) m (locationify p)
-
-prologifyArgiForCall' :: Location -> Word -> Location -> String
-prologifyArgiForCall' a i c = printf "kb_arg_i_for_call( %s, %u, %s )." (locationify a) i (locationify c)
-
-prologifyArgiForCall :: ArgiForCall -> String
-prologifyArgiForCall (ArgiForCall (Arg a) (ArgIndex i) (Call c)) = prologifyArgiForCall' a i c
-
-prologify_ClassAnnotation' :: Location -> Location -> String
-prologify_ClassAnnotation' c a = printf "kb_class_has_annotation( %s, %s )." (locationify c) (locationify a)
-
-prologify_ClassAnnotation :: ClassAnnotation -> String
-prologify_ClassAnnotation (ClassAnnotation (Class c) (Annotation a)) = prologify_ClassAnnotation' c a
-
-prologify_KeywordArgForCall' ::  String -> Location -> Location -> String
-prologify_KeywordArgForCall' kw a c = printf "kb_keyword_arg_for_call( %s, %s, %s )." (locationify a) kw (locationify c)
-
-prologify_KeywordArgForCall :: KeywordArgForCall -> String
-prologify_KeywordArgForCall (KeywordArgForCall (Keyword kw) (Arg a) (Call c)) = prologify_KeywordArgForCall' kw a c
-
-prologify_CallableAnnotation' :: Location -> Location -> String
-prologify_CallableAnnotation' c a = printf "kb_callable_has_annotation( %s, %s )." (locationify c) (locationify a)
-
-prologify_CallableAnnotation :: CallableAnnotation -> String
-prologify_CallableAnnotation (CallableAnnotation (Callable c) (Annotation a)) = prologify_CallableAnnotation' c a
-
-prologify_CallableSourceBodyLength' :: Location -> Word -> String
-prologify_CallableSourceBodyLength' c n = printf "kb_callable_source_body_length( %s, %u )." (locationify c) n
-
-prologify_CallableSourceBodyLength :: CallableSourceBodyLength -> String
-prologify_CallableSourceBodyLength (CallableSourceBodyLength (Callable c) n) = prologify_CallableSourceBodyLength' c n
-
-prologify_ParamiOfCallable' :: Location -> Word -> Location -> String
-prologify_ParamiOfCallable' p i c = printf "kb_param_i_of_callable( %s, %u, %s )." (locationify p) i (locationify c)
-
-prologify_ParamiOfCallable :: ParamiOfCallable -> String
-prologify_ParamiOfCallable (ParamiOfCallable (Param p) (ParamIndex i) (Callable c)) = prologify_ParamiOfCallable' p i c
-
-prologify_CalledFrom' :: Location -> Location -> String
-prologify_CalledFrom' call callable = printf "kb_called_from( %s, %s )." (locationify call) (locationify callable)
-
-prologify_CalledFrom :: CalledFrom -> String
-prologify_CalledFrom (CalledFrom (Call call) (Callable callable)) = prologify_CalledFrom' call callable
-
-normalizeChar :: Char -> String
-normalizeChar '/' = "_slash_"
-normalizeChar '.' = "_dot_"
-normalizeChar '-' = "_dash_"
-normalizeChar '['  = "_lbrack_"
-normalizeChar ']'  = "_rbrack_"
-normalizeChar '('  = "_lparen_"
-normalizeChar ')'  = "_rparen_"
-normalizeChar c = [c]
-
-normalize :: FilePath -> FilePath
-normalize path = concatMap normalizeChar path
-
-prologifyFqn :: Fqn.Fqn -> String
-prologifyFqn (Fqn.ThirdPartyImport fqn) = prologifyThirdPartyImport fqn
-prologifyFqn (Fqn.FieldedAccess fqn fieldName) = prologifyFieldedAccess fqn fieldName
-prologifyFqn fqn = show fqn
-
-prologifyThirdPartyImport :: Fqn.ThirdPartyImportContent -> String
-prologifyThirdPartyImport (Fqn.ThirdPartyImportContent p [] Nothing _) = p
-prologifyThirdPartyImport (Fqn.ThirdPartyImportContent p [] (Just name) _) = p ++ "." ++ name
-prologifyThirdPartyImport (Fqn.ThirdPartyImportContent p rest Nothing _) = p ++ "." ++ List.intercalate "." rest
-prologifyThirdPartyImport (Fqn.ThirdPartyImportContent p rest (Just name) _) = p ++ "." ++ List.intercalate "." rest ++ "." ++ name
-
-prologifyFieldedAccess :: Fqn.Fqn -> Token.FieldName -> String
-prologifyFieldedAccess fqn (Token.FieldName (Token.Named fieldName _)) = (prologifyFqn fqn) ++ "." ++ fieldName
-
-locationify :: Location -> String
-locationify l = let
-    x = Location.lineStart l
-    y = Location.colStart l
-    z = Location.lineEnd l
-    w = Location.colEnd l
-    f = normalize (Location.filename l)
-    in printf "startloc_%u_%u_endloc_%u_%u_%s" x y z w f
-
-restoreloc :: String -> Maybe Location
-restoreloc s = case parseOnly locationParser (T.pack s) of { Right l -> Just l; _ -> Nothing; }
-
-locationParser :: Parser Location
-locationParser = do {
-
-    _ <- string "startloc_"; x <- decimal; _ <- char '_'; y <- decimal;
-    _ <- string "_endloc_" ; z <- decimal; _ <- char '_'; w <- decimal;
-    _ <- char '_'; fname <- takeText;
-
-    pure Location {
-        filename  = restoreFilename (T.unpack fname),
-        lineStart = x,
-        colStart = y,
-        lineEnd = z,
-        colEnd = w
-    }
-}
-
-data Rule = Rule { from :: Text, to :: Text }
-
-rules :: [ Rule ]
-rules =
-    [ Rule { from = "_slash_",  to = "/" }
-    , Rule { from = "_dot_",    to = "." }
-    , Rule { from = "_dash_",   to = "-" }
-    , Rule { from = "_lbrack_", to = "[" }
-    , Rule { from = "_rbrack_", to = "]" }
-    , Rule { from = "_lparen_", to = "(" }
-    , Rule { from = "_rparen_", to = ")" }
-    ]
-
-applyRule :: Rule -> Text -> Text
-applyRule Rule { from = f, to = t } = T.replace f t
-
-applyRuleStep :: Text -> Rule -> Text
-applyRuleStep acc r = applyRule r acc
-
-restore :: Text -> Text
-restore txt = List.foldl' applyRuleStep txt rules
-
-textToStringAdapter :: (Text -> Text) -> String -> String
-textToStringAdapter f = T.unpack . f . T.pack
-
-restoreFilename :: String -> String
+-- |
+--
+-- * The [knowledge base](https://en.wikipedia.org/wiki/Knowledge_representation_and_reasoning) ( kb )
+--   aims to be a data structure able to:
+--
+--     * represent /multiple/ facts about the source code repo
+--     * from /various/ programming languages
+--     * each fact can be translated to a [Prolog](https://en.wikipedia.org/wiki/Prolog) fact
+--     * facts can be combined to create [predicates](https://en.wikipedia.org/wiki/Predicate_%28logic%29)
+--     * [predicates](https://en.wikipedia.org/wiki/Predicate_%28logic%29) can be combined to formulate /security queries/
+--
+-- * Facts describe relations between:
+--
+--     * code locations
+--     * const strings
+--     * const integers
+--
+-- * Code locations are capable of representing /all/ program entities
+--
+--     * classes
+--     * methods
+--     * lambdas
+--     * annotations
+--     * arguments
+--     * parameters
+--     * etc.
+--
+-- * Facts can be /combined/:
+--
+--     * [conjunction](https://en.wikipedia.org/wiki/Logical_conjunction)
+--     * [disjunction](https://en.wikipedia.org/wiki/Logical_disjunction)
+--     * [negation](https://en.wikipedia.org/wiki/Negation)
+--
+-- * [Prolog](https://en.wikipedia.org/wiki/Prolog) queries are /easy/ to write:
+--
+--     * you /don't/ have to be a Prolog expert
+--     * copy-paste the basic facts to /any/ [LLM](https://en.wikipedia.org/wiki/Large_language_model)
+--     * explain in plain English your query's purpose
+--     * et voilà !
+--
+-- * Its main purpose is to serve as the:
+--
+--     * penultimate step for /static code analysis/ 
+--     * part of the [dhscanner](https://github.com/OrenGitHub/dhscanner.vps) framework
+--
+--         * [SAST](https://en.wikipedia.org/wiki/Static_application_security_testing) for security scans 🔒
+--         * [PII](https://en.wikipedia.org/wiki/Personal_data) leaks detection 🪪
+--
+
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE DeriveAnyClass #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+module Kbgen (
+    KeywordArgForCall(..),
+    ParamResolvedType(..),
+    ClassDef(..),
+    FuncDef(..),
+    Call1stPartyFuncDefinedInDir(..),
+    AssignValueToToplevelVarName(..),
+    Call1stPartyFuncDefinedInFile(..),
+    ParamName(..),
+    CallMethodOfClass(..),
+    ConstString(..),
+    ConstInteger(..),
+    MethodOfClass(..),
+    ClassHas1stPartySuper(..),
+    ClassHas3rdPartySuper(..),
+    CallMethodOfUntypedNamedParam(..),
+    ArgiForCall(..),
+    DataflowEdge(..),
+    ConstBoolTrue(..),
+    ConstNull(..),
+    GatedReturn(..),
+    Comparison(..),
+    CallableReturnsValue(..),
+    CallableReturnsWithoutValue(..),
+    Cond(..),
+    Lhs(..),
+    Rhs(..),
+    ComparisonOp(..),
+    ReturnedValue(..),
+    ClassAnnotation(..),
+    CallableAnnotation(..),
+    Annotation(..),
+    CallableSourceBodyLength(..),
+    ParamiOfCallable(..),
+    prologify,
+    To(..),
+    Arg(..),
+    From(..),
+    Func(..),
+    Call(..),
+    Class(..),
+    Param(..),
+    Method(..),
+    Callable(..),
+    Keyword(..),
+    Resolved(..),
+    ArgIndex(..),
+    ParamIndex(..),
+    FuncName(..),
+    MethodName(..),
+    ResolvedType(..),
+    CallResolved(..),
+    CalledFrom(..),
+    AssignedValue(..),
+    ResolvedSuper(..),
+    FuncDefinedInDir(..),
+    FuncDefinedInFile(..),
+    ClassDefinedInFile(..),
+    SuperDefinedInFile(..),
+    SuperQualifiedName(..),
+    ConstStr(..),
+    ConstInt(..),
+    Fact(..),
+    locationify,
+    restoreloc
+)
+
+where
+
+-- general imports
+import Data.Aeson
+import Text.Printf
+import GHC.Generics (Generic)
+import System.FilePath (takeDirectory)
+import Data.Attoparsec.Text (Parser, char, decimal, parseOnly, string, takeText)
+import Data.Text (Text)
+import qualified Data.Text as T
+
+-- general qualified imports
+import qualified Data.List as List
+
+-- project imports
+import Location
+import qualified Token
+import qualified Fqn
+
+-- |
+--
+-- __Name__
+--
+-- This is how the fact will look inside the Prolog file
+--
+-- @
+-- kb_keyword_arg_for_call( Keyword, Arg, Call ).
+-- @
+--
+-- __When should I use this fact__ ( motivation: [CVE-2024-52803](https://nvd.nist.gov/vuln/detail/CVE-2024-52803) )
+--
+-- Code snippet ( Python ):
+--
+-- @
+-- Popen(f'llamafactory-cli train {save_cmd(args)}', env=env, shell=True)
+-- @
+--
+-- See complete source example: [here](https://github.com/hiyouga/LLaMA-Factory/commit/b3aa80d54a67da45e9e237e349486fb9c162b2ac)
+--
+-- __Writing a predicate with this fact and others__ ( motivation: [CVE-2024-52803](https://nvd.nist.gov/vuln/detail/CVE-2024-52803) )
+--
+-- @
+-- subprocess_Popen_called_with_shell_eq_True( Call ) :-
+--     kb_keyword_arg_for_call( \'shell\', TrueValue, Call ),
+--     kb_call_resolved( Call, \'subprocess.Popen\' ),
+--     kb_const_bool_true( TrueValue ).
+-- @
+--
+-- Other facts combined in this example predicate:
+--
+--     * 'CallResolved'
+--     * 'ConstBoolTrue'
+--
+data KeywordArgForCall = KeywordArgForCall
+    Keyword -- ^
+    Arg -- ^
+    Call -- ^
+    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+
+-- |
+--
+-- __Name__
+--
+-- This is how the fact will look inside the Prolog file
+--
+-- @
+-- kb_param_has_resolved_type( Param, ResolvedType ).
+-- @
+--
+-- __When should I use this fact__ ( motivation: [CVE-2024-49380](https://nvd.nist.gov/vuln/detail/CVE-2024-49380) )
+--
+-- Code snippet ( Golang ):
+--
+-- @
+-- func postLocal(w http.ResponseWriter, r *http.Request) { ... }
+-- @
+--
+-- See complete source example: [here](https://github.com/plentico/plenti/blob/01825e0dcd3505fac57adc2edf29f772d585c008/cmd/serve.go#L205)
+--
+-- __Writing a predicate with this fact and others__ ( motivation: [CVE-2024-49380](https://nvd.nist.gov/vuln/detail/CVE-2024-49380) )
+--
+-- @
+-- looks_like_user_input( RequestParam ) :-
+--     kb_param_has_resolved_type( RequestParam, \'net/http.Request\' ),
+--     kb_param_has_resolved_type( ResponseParam, \'net/http.ResponseWriter\' ),
+--     kb_param_i_of_callable( ResponseParam, 0, Handler ),
+--     kb_param_i_of_callable( RequestParam, 1, Handler ).
+-- @
+--
+-- Other facts combined in this predicate:
+--
+--     * 'ParamiOfCallable'
+--
+data ParamResolvedType = ParamResolvedType
+    Param -- ^
+    ResolvedType -- ^
+    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+
+-- |
+--
+-- __Name__
+--
+-- This is how the fact will look inside the Prolog file
+--
+-- @
+-- kb_class_def( Class, Name, DefinedInFile ).
+-- @
+--
+-- __When should I use this fact__ ( motivation: [CVE-2024-53995](https://nvd.nist.gov/vuln/detail/CVE-2024-53995) )
+--
+-- @
+-- # authentication.py
+-- class LoginHandler(BaseHandler): ...
+--
+-- # index.py
+-- from tornado.web import RequestHandler
+-- class BaseHandler(RequestHandler): ...
+-- @
+--
+-- See complete source example [here](https://github.com/SickChill/sickchill/blob/846adafdfab579281353ea08a27bbb813f9a9872/sickchill/views/authentication.py#L10),
+-- [here](https://github.com/SickChill/sickchill/blob/846adafdfab579281353ea08a27bbb813f9a9872/sickchill/views/index.py#L35)
+-- and [here](https://github.com/SickChill/sickchill/blob/846adafdfab579281353ea08a27bbb813f9a9872/sickchill/views/index.py#L15)
+--
+-- __Writing a predicate with this fact and others__ ( motivation: [CVE-2024-53995](https://nvd.nist.gov/vuln/detail/CVE-2024-53995) )
+--
+-- @
+-- skip_level_subclass_of( Subclass, \'tornado.web.RequestHandler\' ) :-
+--     kb_class_def( Subclass, _, _ ),
+--     kb_class_has_1st_party_super( Subclass, ClassName, ClassDefinedInFile ),
+--     kb_class_def( Class, ClassName, ClassDefinedInFile )
+--     kb_class_has_3rd_party_super( Class, _, \'tornado.web.RequestHandler\' ).
+-- @
+--
+-- Other facts combined in this predicate:
+--
+--     * 'ClassHas1stPartySuper'
+--     * 'ClassHas3rdPartySuper'
+--
+data ClassDef = ClassDef
+    Class -- ^
+    Token.ClassName -- ^
+    ClassDefinedInFile -- ^
+    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+
+-- |
+--
+-- __Name__
+--
+-- This is how the fact will look inside the Prolog file
+--
+-- @
+-- kb_func_def( Func, Name, DefinedInFile, DefinedInDir ).
+-- @
+--
+-- __When should I use this fact__ ( motivation: [CVE-2024-29028](https://nvd.nist.gov/vuln/detail/CVE-2024-29028) )
+--
+-- @
+-- # http_getter.go
+-- g.GET("/get/httpmeta", func(c echo.Context) error {
+--     urlStr := c.QueryParam("url")
+--     ...
+--     getter.GetHTMLMeta(urlStr)
+--
+-- # html_meta.go
+-- func GetHTMLMeta(urlStr string) (*HTMLMeta, error) {
+--     ...
+--     http.Get(urlStr)
+-- @
+--
+-- See complete source example [here](https://github.com/usememos/memos/blob/v0.14.0/api/v1/http_getter.go#L23),
+-- and [here](https://github.com/usememos/memos/blob/v0.14.0/plugin/http-getter/html_meta.go#L24)
+--
+-- __Writing a predicate with this fact and others__ ( motivation: [CVE-2024-29028](https://nvd.nist.gov/vuln/detail/CVE-2024-29028) )
+--
+-- @
+-- suspected_ssrf_sink( Func ) :-
+--     kb_resolved_call( Call, \'net/http.Get\' ),
+--     kb_arg_i_for_call( Arg, 0, Call ),
+--     utils_dataflow_path( Param, Arg ),
+--     kb_param_has_resolved_type( Param, \'string\' ),
+--     kb_param_i_of_callable( Param, _, Func ),
+--     kb_func_def( Func, Name, _, FuncDefinedInDir ),
+--     kb_call_1st_party_func_defined_in_dir( _, Name, FuncDefinedInDir ).
+-- @
+--
+-- Other facts combined in this predicate:
+--
+--     * 'CallResolved'
+--     * 'ArgiForCall'
+--     * 'ParamResolvedType'
+--     * 'ParamiOfCallable'
+--     * 'Call1stPartyFuncDefinedInDir'
+--
+data FuncDef = FuncDef
+    Func -- ^
+    Token.FuncName -- ^
+    FuncDefinedInFile -- ^
+    FuncDefinedInDir -- ^
+    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+
+-- |
+--
+-- __Name__
+--
+-- This is how the fact will look inside the Prolog file
+--
+-- @
+-- kb_call_1st_party_func_defined_in_dir( Call, Name, DefinedInDir ).
+-- @
+--
+-- __When should I use this fact__ ( motivation: [CVE-2024-29028](https://nvd.nist.gov/vuln/detail/CVE-2024-29028) )
+--
+-- @
+-- # http_getter.go
+-- g.GET("/get/httpmeta", func(c echo.Context) error {
+--     urlStr := c.QueryParam("url")
+--     ...
+--     getter.GetHTMLMeta(urlStr)
+--
+-- # html_meta.go
+-- func GetHTMLMeta(urlStr string) (*HTMLMeta, error) {
+--     ...
+--     http.Get(urlStr)
+-- @
+--
+-- See complete source example [here](https://github.com/usememos/memos/blob/v0.14.0/api/v1/http_getter.go#L23),
+-- and [here](https://github.com/usememos/memos/blob/v0.14.0/plugin/http-getter/html_meta.go#L24)
+--
+-- __Writing a predicate with this fact and others__ ( motivation: [CVE-2024-29028](https://nvd.nist.gov/vuln/detail/CVE-2024-29028) )
+--
+-- @
+-- suspected_ssrf_sink( Func ) :-
+--     kb_resolved_call( Call, \'net/http.Get\' ),
+--     kb_arg_i_for_call( Arg, 0, Call ),
+--     utils_dataflow_path( Param, Arg ),
+--     kb_param_has_resolved_type( Param, \'string\' ),
+--     kb_param_i_of_callable( Param, _, Func ),
+--     kb_func_def( Func, Name, _, FuncDefinedInDir ),
+--     kb_call_1st_party_func_from_dir( _, Name, FuncDefinedInDir ).
+-- @
+--
+-- Other facts combined in this predicate:
+--
+--     * 'CallResolved'
+--     * 'ArgiForCall'
+--     * 'ParamResolvedType'
+--     * 'ParamiOfCallable'
+--
+data Call1stPartyFuncDefinedInDir = Call1stPartyFuncDefinedInDir
+    Call -- ^
+    FuncName -- ^
+    FuncDefinedInDir -- ^
+    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+
+data Call1stPartyFuncDefinedInFile = Call1stPartyFuncDefinedInFile
+    Call -- ^
+    FuncName -- ^
+    FuncDefinedInFile -- ^
+    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+
+data AssignValueToToplevelVarName = AssignValueToToplevelVarName
+    AssignedValue -- ^
+    Token.VarName -- ^
+    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+
+-- |
+--
+-- __Description:__
+--
+-- Input parameter of some callable ( method, function, lambda ) has the specified name
+--
+-- __Prolog signature:__
+--
+-- @
+-- kb_param_has_name( Param, Name ).
+-- @
+--
+-- __Code Example ( Javascript ):__
+--
+-- Motivated by [GHSL-2023-203](https://github.com/advplyr/audiobookshelf/security/advisories/GHSA-mgj7-rfx8-vhpr#event-116560)
+-- ( [source code](https://github.com/advplyr/audiobookshelf/blob/d7b2476473ef1934eedec41425837cddf2d4b13e/server/controllers/AuthorController.js#L66)
+-- and see also [here](https://github.com/advplyr/audiobookshelf/blob/d7b2476473ef1934eedec41425837cddf2d4b13e/server/controllers/AuthorController.js#L74)
+-- and [here](https://github.com/advplyr/audiobookshelf/blob/d7b2476473ef1934eedec41425837cddf2d4b13e/server/routers/ApiRouter.js#L201) )
+--
+-- @
+-- // ApiRouter.js
+-- const express = require(\'express\')
+--
+-- class ApiRouter {
+--   constructor(Server) { this.router = express() }
+--   init() { this.router.patch(\'\/authors\/:id', ... , AuthorController.update.bind(this)) }
+--
+-- // AuthorController.js
+-- class AuthorController { async update(req, res) { ... } }
+-- @
+--
+-- __Writing new predicates:__
+--
+-- Facts combined in this predicate:
+--
+--     * 'ParamName'
+--     * 'ParamiOfCallable'
+--
+-- @
+-- http_request_param_of_method( Param, Method ) :-
+--     kb_param_name( Param, \'req\' ),
+--     kb_param_name( SecondParam, \'res\' ),
+--     kb_param_i_of_callable( Param, 0, Method ),
+--     kb_param_i_of_callable( SecondParam, 1, Method ).
+-- @
+--
+-- Facts combined in this predicate:
+--
+--     * 'ArgiForCall'
+--     * 'ClassName'
+--     * 'MethodName'
+--
+-- @
+-- request_handler( Method ) :-
+--     kb_resolved_call( Call, \'express.patch\' ),
+--     kb_arg_i_for_call( RequestHandler, 2, Call ),
+--     kb_resolved_part_i_call( RequestHandler, 0, ClassName ),
+--     kb_resolved_part_i_call( RequestHandler, 1, MethodName ),
+--     kb_method_of_class( Method, Class ),
+--     kb_method_name( Method, MethodName ),
+--     kb_class_name( Class, ClassName ).
+-- @
+--
+--
+data ParamName = ParamName
+    Param -- ^
+    Token.ParamName -- ^
+    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+
+-- |
+--
+-- __Name__
+--
+-- This is how the fact will look inside the Prolog file
+--
+-- @
+-- kb_class_has_1st_party_super( Class, SuperName, SuperDefinedInFile ).
+-- @
+--
+-- __When should I use this fact__ ( motivation: [CVE-2024-53995](https://nvd.nist.gov/vuln/detail/CVE-2024-53995) )
+--
+-- @
+-- # authentication.py
+-- class LoginHandler(BaseHandler): ...
+--
+-- # index.py
+-- from tornado.web import RequestHandler
+-- class BaseHandler(RequestHandler): ...
+-- @
+--
+-- See complete source example [here](https://github.com/SickChill/sickchill/blob/846adafdfab579281353ea08a27bbb813f9a9872/sickchill/views/authentication.py#L10),
+-- [here](https://github.com/SickChill/sickchill/blob/846adafdfab579281353ea08a27bbb813f9a9872/sickchill/views/index.py#L35)
+-- and [here](https://github.com/SickChill/sickchill/blob/846adafdfab579281353ea08a27bbb813f9a9872/sickchill/views/index.py#L15)
+--
+-- __Writing a predicate with this fact and others__ ( motivation: [CVE-2024-53995](https://nvd.nist.gov/vuln/detail/CVE-2024-53995) )
+--
+-- @
+-- skip_level_subclass_of( Subclass, \'tornado.web.RequestHandler\' ) :-
+--     kb_class_def( Subclass, _, _ ),
+--     kb_class_has_1st_party_super( Subclass, ClassName, ClassDefinedInFile ),
+--     kb_class_def( Class, ClassName, ClassDefinedInFile )
+--     kb_class_has_3rd_party_super( Class, _, \'tornado.web.RequestHandler\' ).
+-- @
+--
+-- Other facts combined in this predicate:
+--
+--     * 'ClassDef'
+--     * 'ClassHas3rdPartySuper'
+--
+data ClassHas1stPartySuper = ClassHas1stPartySuper
+    Class -- ^
+    Token.SuperName -- ^
+    SuperDefinedInFile -- ^
+    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+
+-- |
+--
+-- __Name__
+--
+-- This is how the fact will look inside the Prolog file
+--
+-- @
+-- kb_class_has_3rd_party_super( Class, SuperName, SuperQualifiedName ).
+-- @
+--
+-- __When should I use this fact__ ( motivation: [CVE-2024-53995](https://nvd.nist.gov/vuln/detail/CVE-2024-53995) )
+--
+-- @
+-- # authentication.py
+-- class LoginHandler(BaseHandler): ...
+--
+-- # index.py
+-- from tornado.web import RequestHandler
+-- class BaseHandler(RequestHandler): ...
+-- @
+--
+-- See complete source example [here](https://github.com/SickChill/sickchill/blob/846adafdfab579281353ea08a27bbb813f9a9872/sickchill/views/authentication.py#L10),
+-- [here](https://github.com/SickChill/sickchill/blob/846adafdfab579281353ea08a27bbb813f9a9872/sickchill/views/index.py#L35)
+-- and [here](https://github.com/SickChill/sickchill/blob/846adafdfab579281353ea08a27bbb813f9a9872/sickchill/views/index.py#L15)
+--
+-- __Writing a predicate with this fact and others__ ( motivation: [CVE-2024-53995](https://nvd.nist.gov/vuln/detail/CVE-2024-53995) )
+--
+-- @
+-- skip_level_subclass_of( Subclass, \'tornado.web.RequestHandler\' ) :-
+--     kb_class_def( Subclass, _, _ ),
+--     kb_class_has_1st_party_super( Subclass, ClassName, ClassDefinedInFile ),
+--     kb_class_def( Class, ClassName, ClassDefinedInFile )
+--     kb_class_has_3rd_party_super( Class, _, \'tornado.web.RequestHandler\' ).
+-- @
+--
+-- Other facts combined in this predicate:
+--
+--     * 'ClassDef'
+--     * 'ClassHas1stPartySuper'
+--
+data ClassHas3rdPartySuper = ClassHas3rdPartySuper
+    Class -- ^
+    Token.SuperName -- ^
+    SuperQualifiedName -- ^
+    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+
+-- |
+--
+-- __Name__
+--
+-- This is how the fact will look inside the Prolog file
+--
+-- @
+-- kb_call_method_of_class( Call, Method, Class ).
+-- @
+--
+-- __When should I use this fact__ ( motivation: [CVE-2024-53995](https://nvd.nist.gov/vuln/detail/CVE-2024-53995) )
+--
+-- @
+-- # index.py
+-- from tornado.web import RequestHandler
+-- class BaseHandler(RequestHandler): ...
+--
+-- # authentication.py
+-- class LoginHandler(BaseHandler):
+--     def post(self, ...):
+--         n = self.get_query_argument("next", ...)
+--         self.redirect(n or ...)
+-- @
+--
+-- See complete source example [here](https://github.com/SickChill/sickchill/blob/846adafdfab579281353ea08a27bbb813f9a9872/sickchill/views/authentication.py#L10),
+-- [here](https://github.com/SickChill/sickchill/blob/846adafdfab579281353ea08a27bbb813f9a9872/sickchill/views/index.py#L35)
+-- and [here](https://github.com/SickChill/sickchill/blob/846adafdfab579281353ea08a27bbb813f9a9872/sickchill/views/index.py#L15)
+--
+-- __Writing a predicate with this fact and others__ ( motivation: [CVE-2024-53995](https://nvd.nist.gov/vuln/detail/CVE-2024-53995) )
+--
+-- @
+-- user_controlled_query_argument( Call ) :-
+--     kb_call_method_of_class( Call, \'get_query_argument\', Class ),
+--     kb_class_has_3rd_party_super( Class, \'tornado.web.RequestHandler\'),
+--     kb_arg_i_for_call( QueryParamName, 0, Call),
+--     kb_const_string( QueryParamName, _ ).
+-- @
+--
+-- Other facts combined in this predicate:
+--
+--     * 'ClassHas3rdPartySuper'
+--     * 'ArgiForCall'
+--     * 'ConstString'
+--
+data CallMethodOfClass = CallMethodOfClass
+    Call -- ^
+    MethodName -- ^
+    Class -- ^
+    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+
+-- |
+--
+-- __Name__
+--
+-- This is how the fact will look inside the Prolog file
+--
+-- @
+-- kb_call_method_of_untyped_named_param( Param, ParamName, MethodName ).
+-- @
+--
+-- __When should I use this fact__ ( motivation: [CVE-2024-47769](https://nvd.nist.gov/vuln/detail/CVE-2024-47769) )
+--
+-- @
+-- // corePublicRouter.js
+-- const express = require('express');
+-- const router = express.Router();
+--
+-- router.route('...').get(function (req, res) {
+--     const { ..., file } = req.params;
+--     const fileName = file;
+--     return res.sendFile(fileName, ...);
+-- }
+-- @
+--
+-- See complete source example [here](https://github.com/idurar/idurar-erp-crm/blob/d7b2215a17bb2b52acfdab8f1646685d13df9a00/backend/src/routes/coreRoutes/corePublicRouter.js#L8-L24),
+--
+-- __Writing a predicate with this fact and others__ ( motivation: [CVE-2024-47769](https://nvd.nist.gov/vuln/detail/CVE-2024-47769) )
+--
+-- @
+-- arbitrary_file_read( Call ) :-
+--     kb_call_resolved( Call, \'express.Router.route.get\'),
+--     kb_call_method_of_untyped_named_param( Param, \'res\', \'sendFile\' ),
+--     kb_arg_i_for_call( Lambda, 0, Call ),
+--     kb_param_i_of_callable( Param, 1, Lambda ).
+-- @
+--
+-- Other facts combined in this predicate:
+--
+--     * 'CallResolved'
+--     * 'ArgiForCall'
+--     * 'ParamiOfCallable'
+--
+data CallMethodOfUntypedNamedParam = CallMethodOfUntypedNamedParam
+    Call -- ^
+    MethodName -- ^
+    Token.ParamName -- ^
+    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+
+-- |
+-- capture inheritance from third party classes
+data ClassAnnotation = ClassAnnotation
+    Class -- ^
+    Annotation -- ^
+    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+
+data CallableAnnotation = CallableAnnotation
+    Callable -- ^
+    Annotation -- ^
+    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+
+-- |
+--
+-- __Name__
+--
+-- This is how the fact will look inside the Prolog file
+--
+-- @
+-- kb_callable_source_body_length( Callable, N ).
+-- @
+--
+-- Number of source-level @[ Ast.Stmt ]@ statements in the callable's body,
+-- as observed at codegen time (before any lowering to bitcode). Independent
+-- of how many bitcode instructions the body lowered to.
+--
+-- Intended for query predicates that need a source-fidelity signal ( e.g.
+-- \"this wrapper's source body is a single statement\" for HOC-unwrap ),
+-- rather than trying to reconstruct that shape from flat SSA bitcode after
+-- the fact.
+--
+-- Emitted for 'Method', 'Lambda' and 'Function' callables. Not emitted for
+-- 'Script' \-- see 'Callable.numOriginalSourceInstructions'.
+data CallableSourceBodyLength = CallableSourceBodyLength
+    Callable -- ^
+    Word -- ^ number of source-level statements in the body
+    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+
+-- |
+-- capture usage of inherited third party methods
+data MethodOfClass = MethodOfClass
+    Method -- ^
+    Class -- ^
+    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+
+-- |
+--
+-- __Name__
+--
+-- This is how the fact will look inside the Prolog file
+--
+-- @
+-- kb_arg_i_for_call( Arg, Index, Call ).
+-- @
+--
+-- __When should I use this fact__ ( motivation: [CVE-2024-47769](https://nvd.nist.gov/vuln/detail/CVE-2024-47769) )
+--
+-- @
+-- // corePublicRouter.js
+-- const express = require('express');
+-- const router = express.Router();
+--
+-- router.route('...').get(function (req, res) {
+--     const { ..., file } = req.params;
+--     const fileName = file;
+--     return res.sendFile(fileName, ...);
+-- }
+-- @
+--
+-- See complete source example [here](https://github.com/idurar/idurar-erp-crm/blob/d7b2215a17bb2b52acfdab8f1646685d13df9a00/backend/src/routes/coreRoutes/corePublicRouter.js#L8-L24),
+--
+-- __Writing a predicate with this fact and others__ ( motivation: [CVE-2024-47769](https://nvd.nist.gov/vuln/detail/CVE-2024-47769) )
+--
+-- @
+-- arbitrary_file_read( Call ) :-
+--     kb_call_resolved( Call, \'express.Router.route.get\'),
+--     kb_call_method_of_untyped_named_param( Param, \'res\', \'sendFile\' ),
+--     kb_arg_i_for_call( Lambda, 0, Call ),
+--     kb_param_i_of_callable( Param, 1, Lambda ).
+-- @
+--
+-- Other facts combined in this predicate:
+--
+--     * 'CallResolved'
+--     * 'CallMethodOfUntypedNamedParam'
+--     * 'ParamiOfCallable'
+--
+-- ==== __Tip 💡__
+--
+-- When the exact index is irrelevant, use:
+--
+-- @
+-- kb_arg_i_for_call( Arg, _, Call ).
+-- @
+--
+data ArgiForCall = ArgiForCall
+    Arg -- ^
+    ArgIndex -- ^
+    Call -- ^
+    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+
+-- |
+--
+-- __Name__
+--
+-- This is how the fact will look inside the Prolog file
+--
+-- @
+-- kb_param_i_of_callable( Param, Index, Callable ).
+-- @
+--
+-- __When should I use this fact__ ( motivation: [CVE-2024-29028](https://nvd.nist.gov/vuln/detail/CVE-2024-29028) )
+--
+-- @
+-- # http_getter.go
+-- g.GET("/get/httpmeta", func(c echo.Context) error {
+--     urlStr := c.QueryParam("url")
+--     ...
+--     getter.GetHTMLMeta(urlStr)
+--
+-- # html_meta.go
+-- func GetHTMLMeta(urlStr string) (*HTMLMeta, error) {
+--     ...
+--     http.Get(urlStr)
+-- @
+--
+-- See complete source example [here](https://github.com/usememos/memos/blob/v0.14.0/api/v1/http_getter.go#L23),
+-- and [here](https://github.com/usememos/memos/blob/v0.14.0/plugin/http-getter/html_meta.go#L24)
+--
+-- __Writing a predicate with this fact and others__ ( motivation: [CVE-2024-29028](https://nvd.nist.gov/vuln/detail/CVE-2024-29028) )
+--
+-- @
+-- suspected_ssrf_sink( Func ) :-
+--     kb_resolved_call( Call, \'net/http.Get\' ),
+--     kb_arg_i_for_call( Arg, 0, Call ),
+--     utils_dataflow_path( Param, Arg ),
+--     kb_param_has_resolved_type( Param, \'string\' ),
+--     kb_param_i_of_callable( Param, _, Func ),
+--     kb_func_def( Func, Name, _, FuncDefinedInDir ),
+--     kb_call_1st_party_func_defined_in_dir( _, Name, FuncDefinedInDir ).
+-- @
+--
+-- Other facts combined in this predicate:
+--
+--     * 'CallResolved'
+--     * 'ArgiForCall'
+--     * 'ParamResolvedType'
+--     * 'FuncDef'
+--     * 'Call1stPartyFuncDefinedInDir'
+--
+-- ==== __Tip 💡__
+--
+-- When the _exact index_ is _irrelevant_, use:
+--
+-- @
+-- kb_param_i_of_callable( Param, _, Callable ).
+-- @
+--
+data ParamiOfCallable = ParamiOfCallable
+    Param -- ^
+    ParamIndex -- ^ 0-based
+    Callable -- ^
+    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+
+data CallResolved = CallResolved
+    Call -- ^
+    Resolved -- ^
+    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+
+-- |
+--
+-- __Name__
+--
+-- This is how the fact will look inside the Prolog file
+--
+-- @
+-- kb_called_from( Call, Callable ).
+-- @
+--
+-- __When should I use this fact__
+--
+-- Web-app request handlers routinely /extract fields/ from the incoming
+-- request \- headers, cookies, query parameters, body \- and the /name/
+-- of the field is often the security-relevant piece ( e.g. the constant
+-- string \'x-api-key\' says "this callable does API-key authentication" ).
+-- To reason about /which/ callable extracts /which/ field, you need to
+-- know that a particular call site lives inside the body of a particular
+-- callable.
+--
+-- No pre-existing fact tied a 'Call' back to its enclosing 'Callable' \-
+-- 'ParamiOfCallable' does the analogous thing for /parameters/ only.
+-- Because 'CalledFrom' exposes the 'Call' /location/ ( not just its FQN ),
+-- it composes with 'ArgiForCall' and 'ConstString' to also surface the
+-- /arguments/ passed at that specific call site.
+--
+-- Code snippet ( Typescript, Next.js \- formbricks at v3.16.0 ):
+--
+-- @
+-- export const authenticateRequest = async (request: Request) => {
+--     const apiKey = request.headers.get(\"x-api-key\");
+--     if (!apiKey) return null;
+--     const apiKeyData = await getApiKeyWithPermissions(apiKey);
+--     ...
+-- };
+-- @
+--
+-- See complete source example [here](https://github.com/formbricks/formbricks/blob/v3.16.0/apps/web/app/api/v1/auth.ts#L7-L36)
+--
+-- __Writing a predicate with this fact and others__
+--
+-- Compose 'CalledFrom' with 'ArgiForCall' and 'ConstString' to enumerate
+-- the constant-string header names each callable extracts from the
+-- incoming request:
+--
+-- @
+-- extracts_request_header_named( Callable, HeaderName ) :-
+--     kb_called_from( Call, Callable ),
+--     kb_call_resolved( Call, \'Request.headers.get\' ),
+--     kb_arg_i_for_call( HeaderConst, 0, Call ),
+--     kb_const_string( HeaderConst, HeaderName ).
+-- @
+--
+-- Applied to @authenticateRequest@ above, this yields
+-- @extracts_request_header_named( authenticateRequest, \'x-api-key\' )@ \-
+-- one of the six structural indicators for recognizing Shape-A
+-- ( identity-carrier ) request authenticators.
+--
+-- Other facts combined in this predicate:
+--
+--     * 'CallResolved'
+--     * 'ArgiForCall'
+--     * 'ConstString'
+--
+data CalledFrom = CalledFrom
+    Call -- ^
+    Callable -- ^
+    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+
+
+-- |
+--
+-- Usage:
+--
+-- @
+-- kb_const_str( Param, Index, Callable ).
+-- @
+--
+-- ==== __Tip 💡__
+--
+-- sometimes the exact index is irrelevant, see 'Arg_for_Call'
+--
+data ConstString = ConstString
+    ConstStr -- ^
+    Token.ConstStr -- ^
+    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+
+-- |
+--
+-- __Name__
+--
+-- This is how the fact will look inside the Prolog file
+--
+-- @
+-- kb_const_int( Loc, Value ).
+-- @
+--
+-- __When should I use this fact__
+--
+-- Any time a query needs to discriminate on the /value/ of a constant
+-- integer literal appearing in source code, typically as an argument
+-- to a function that carries semantic information in that integer.
+-- The canonical example is the HTTP status code passed to a response
+-- constructor:
+--
+-- @
+-- return Response.json({ error: \"unauthorized\" }, { status: 401 });
+-- @
+--
+-- Recognizing this shape ( a bad status code returned early from a
+-- callable ) is used to identify authenticating functions.
+--
+-- __Writing a predicate with this fact and others__
+--
+-- @
+-- utils_ts_response_json_with_status( Function, Code ) :-
+--     kb_call_resolved( OuterCall, \'nodejs.Response.json\' ),
+--     kb_arg_i_for_call( DictifyCall, 1, OuterCall ),
+--     kb_arg_i_for_call( KvCall, _, DictifyCall ),
+--     kb_arg_i_for_call( KeyLoc, 0, KvCall ),
+--     kb_const_string( KeyLoc, \'status\' ),
+--     kb_arg_i_for_call( ValueLoc, 1, KvCall ),
+--     kb_const_int( ValueLoc, Code ),
+--     kb_called_from( OuterCall, Function ).
+-- @
+--
+-- Other facts combined in this example predicate:
+--
+--     * 'CallResolved'
+--     * 'ArgiForCall'
+--     * 'ConstString'
+--     * 'CalledFrom'
+--
+data ConstInteger = ConstInteger
+    ConstInt -- ^
+    Token.ConstInt -- ^
+    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+
+-- |
+--
+-- __Name__
+--
+-- This is how the fact will look inside the Prolog file
+--
+-- @
+-- kb_const_null( Loc ).
+-- @
+--
+-- __When should I use this fact__
+--
+-- Returning early from a function with a null value has many uses cases related to security.
+-- ( Python @None@ and Ruby @nil@ use this predicate as well )
+--
+-- __Writing a predicate with this fact and others__
+--
+-- @
+-- kb_gated_return_null( Cond ) :-
+--     kb_gated_return( Cond, ReturnedValue ),
+--     kb_const_null( ReturnedValue ).
+-- @
+--
+-- Other facts combined in this example predicate:
+--
+--     * 'GatedReturn'
+--
+data ConstNull = ConstNull Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+
+-- |
+--
+-- __Name__
+--
+-- This is how the fact will look inside the Prolog file
+--
+-- @
+-- kb_gated_return( Cond, ReturnedValue ).
+-- @
+--
+-- __When should I use this fact__
+--
+-- Authenticating functions reject invalid credentials with an early return
+-- from a guarded @if@. This fact pinpoints that rejection gate.
+--
+-- __Writing a predicate with this fact and others__
+--
+-- @
+-- utils_early_return_null_on_missing_request_header_value( Callable, KeyName ) :-
+--     kb_called_from( Call, Callable ),
+--     kb_call_resolved( Call, \'nodejs.Request.headers.get\' ),
+--     kb_arg_i_for_call( KeyArg, 0, Call ),
+--     kb_const_string( KeyArg, KeyName ),
+--     utils_intra_dataflow_path( Call, Var, _ ),
+--     kb_gated_return_null( Cond ),
+--     utils_intra_dataflow_path( Var, Cond, _ ).
+--
+-- kb_gated_return_null( Cond ) :- kb_gated_return( Cond, RV ), kb_const_null( RV ).
+-- @
+--
+-- Other facts combined in this example predicate:
+--
+--     * 'ConstNull'
+--     * 'CallResolved'
+--     * 'ArgiForCall'
+--     * 'ConstString'
+--     * 'CalledFrom'
+--
+data GatedReturn = GatedReturn
+    Cond -- ^
+    ReturnedValue -- ^
+    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+
+-- |
+--
+-- __Name__
+--
+-- This is how the fact will look inside the Prolog file
+--
+-- @
+-- kb_comparison( Cond, Lhs, Rhs, Op ).
+-- @
+--
+-- __When should I use this fact__
+--
+-- Binary comparison instructions ( currently @==@ \/ @===@ mapped to
+-- the Prolog atom @eq@, and @!=@ \/ @!==@ mapped to @neq@ ) fire this
+-- fact. The @Cond@ slot is the location of the comparison\'s output
+-- variable, which makes composing with 'GatedReturn' straightforward:
+-- when the boolean condition of an @if@ that early-returns is itself a
+-- comparison, both facts share the same location in the @Cond@ slot.
+--
+-- __Writing a predicate with this fact and others__
+--
+-- @
+-- gated_return_on_comparison( Lhs, Rhs, Op, ReturnedValue ) :-
+--     kb_gated_return( Cond, ReturnedValue ),
+--     kb_comparison( Cond, Lhs, Rhs, Op ).
+-- @
+--
+-- Other facts combined in this example predicate:
+--
+--     * 'GatedReturn'
+--
+data Comparison = Comparison
+    Cond -- ^
+    Lhs -- ^
+    Rhs -- ^
+    ComparisonOp -- ^
+    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+
+-- |
+--
+-- __Name__
+--
+-- This is how the fact will look inside the Prolog file
+--
+-- @
+-- kb_callable_returns_value( Callable, ReturnedValue ).
+-- @
+--
+-- __When should I use this fact__
+--
+-- Every explicit `return exp;` inside a callable's body fires this fact
+-- once, keyed by the enclosing callable and the returned expression's
+-- location. Downstream predicates like `kb_const_null` or
+-- `kb_call_resolved` add semantic meaning to the value slot.
+--
+data CallableReturnsValue = CallableReturnsValue
+    Callable -- ^
+    ReturnedValue -- ^
+    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+
+-- |
+--
+-- __Name__
+--
+-- This is how the fact will look inside the Prolog file
+--
+-- @
+-- kb_callable_returns_without_value( Callable, ReturnStmtLocation ).
+-- @
+--
+-- __When should I use this fact__
+--
+-- User-written bare `return;` (no value expression) fires this fact once,
+-- keyed by the enclosing callable and the location of the return
+-- statement itself. Distinct fact from 'CallableReturnsValue' because
+-- there is no value-expression location to anchor on; the return
+-- statement location is used instead.
+--
+data CallableReturnsWithoutValue = CallableReturnsWithoutValue
+    Callable -- ^
+    Location -- ^
+    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+
+-- |
+--
+-- __Name__
+--
+-- This is how the fact will look inside the Prolog file
+--
+-- @
+-- kb_dataflow_edge( From, To ).
+-- @
+--
+data DataflowEdge = DataflowEdge
+    From -- ^
+    To -- ^
+    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+
+data Arg = Arg Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+data Call = Call Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+data Param = Param Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+data Class = Class Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+
+data To = To Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+data From = From Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+data Func = Func Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+data Method = Method Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+data Callable = Callable Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+data ConstStr = ConstStr Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+data ConstInt = ConstInt Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+data Annotation = Annotation Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+data AssignedValue = AssignedValue Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+data ConstBoolTrue = ConstBoolTrue Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+data Cond = Cond Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+data Lhs = Lhs Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+data Rhs = Rhs Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+data ComparisonOp = ComparisonOp String deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+data ReturnedValue = ReturnedValue Location deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+
+data Keyword = Keyword String deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+data Resolved = Resolved Fqn.Fqn deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+data ArgIndex = ArgIndex Word deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+data ParamIndex = ParamIndex Word deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+data FuncName = FuncName String deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+data MethodName = MethodName String deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+data ConstStrValue = ConstStrValue String deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+data SuperQualifiedName = SuperQualifiedName Fqn.Fqn deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+
+data FuncDefinedInDir = FuncDefinedInDir FilePath deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+data FuncDefinedInFile = FuncDefinedInFile FilePath deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+data ClassDefinedInFile = ClassDefinedInFile FilePath deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+data SuperDefinedInFile = SuperDefinedInFile FilePath deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+
+-- |
+data ResolvedType = ResolvedType
+    Fqn.Fqn -- ^
+    deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+
+data ResolvedSuper = ResolvedSuper Fqn.Fqn deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+
+-- |
+-- * each fact is derived from a /single/ bitcode 'Bitcode.Instruction'
+--
+-- * often, a single bitcode instruction will yield /more/ than one fact
+--
+data Fact
+   = FuncDefCtor FuncDef 
+   | ClassDefCtor ClassDef
+   | ParamNameCtor ParamName
+   | ArgiForCallCtor ArgiForCall
+   | ConstStringCtor ConstString
+   | ConstIntegerCtor ConstInteger
+   | DataflowEdgeCtor DataflowEdge
+   | CallResolvedCtor CallResolved
+   | CalledFromCtor CalledFrom
+   | ConstBoolTrueCtor ConstBoolTrue
+   | ConstNullCtor ConstNull
+   | GatedReturnCtor GatedReturn
+   | ComparisonCtor Comparison
+   | CallableReturnsValueCtor CallableReturnsValue
+   | CallableReturnsWithoutValueCtor CallableReturnsWithoutValue
+   | MethodOfClassCtor MethodOfClass
+   | ClassAnnotationCtor ClassAnnotation
+   | ParamiOfCallableCtor ParamiOfCallable
+   | KeywordArgForCallCtor KeywordArgForCall
+   | ParamResolvedTypeCtor ParamResolvedType
+   | CallMethodOfClassCtor CallMethodOfClass
+   | CallableAnnotationCtor CallableAnnotation
+   | ClassHas1stPartySuperCtor ClassHas1stPartySuper
+   | ClassHas3rdPartySuperCtor ClassHas3rdPartySuper
+   | CallableSourceBodyLengthCtor CallableSourceBodyLength
+   | AssignValueToToplevelVarNameCtor AssignValueToToplevelVarName
+   | Call1stPartyFuncDefinedInDirCtor Call1stPartyFuncDefinedInDir
+   | Call1stPartyFuncDefinedInFileCtor Call1stPartyFuncDefinedInFile
+   | CallMethodOfUntypedNamedParamCtor CallMethodOfUntypedNamedParam
+   deriving ( Show, Eq, Ord, Generic, ToJSON, FromJSON )
+
+-- |
+-- Translate a code fact into a prolog fact
+--
+-- 'ParamName'
+--
+-- @
+-- kb_param_has_name( Param, Name ).
+-- @
+--
+prologify :: Fact -> String
+prologify (FuncDefCtor content) = prologify_FuncDef content
+prologify (ClassDefCtor content) = prologify_ClassDef content
+prologify (ParamNameCtor content) = prologify_ParamName content
+prologify (ArgiForCallCtor content) = prologifyArgiForCall content
+prologify (ConstStringCtor content) = prologify_ConstString content
+prologify (ConstIntegerCtor content) = prologify_ConstInteger content
+prologify (DataflowEdgeCtor content) = prologify_DataflowEdge content
+prologify (CallResolvedCtor content) = prologify_CallResolved content
+prologify (CalledFromCtor content) = prologify_CalledFrom content
+prologify (ConstBoolTrueCtor content) = prologify_ConstBoolTrue content
+prologify (ConstNullCtor content) = prologify_ConstNull content
+prologify (GatedReturnCtor content) = prologify_GatedReturn content
+prologify (ComparisonCtor content) = prologify_Comparison content
+prologify (CallableReturnsValueCtor content) = prologify_CallableReturnsValue content
+prologify (CallableReturnsWithoutValueCtor content) = prologify_CallableReturnsWithoutValue content
+prologify (MethodOfClassCtor content) = prologify_MethodOfClass content
+prologify (ClassAnnotationCtor content) = prologify_ClassAnnotation content
+prologify (ParamiOfCallableCtor content) = prologify_ParamiOfCallable content
+prologify (ParamResolvedTypeCtor content) = prologify_ParamResolvedType content
+prologify (CallMethodOfClassCtor content) = prologify_CallMethodOfClass content
+prologify (KeywordArgForCallCtor content) = prologify_KeywordArgForCall content
+prologify (CallableAnnotationCtor content) = prologify_CallableAnnotation content
+prologify (CallableSourceBodyLengthCtor content) = prologify_CallableSourceBodyLength content
+prologify (ClassHas1stPartySuperCtor content) = prologify_ClassHas1stPartySuper content
+prologify (ClassHas3rdPartySuperCtor content) = prologify_ClassHas3rdPartySuper content
+prologify (AssignValueToToplevelVarNameCtor content) = prologify_AssignValueToToplevelVarName content
+prologify (Call1stPartyFuncDefinedInDirCtor content) = prologify_Call1stPartyFuncDefinedInDir content
+prologify (Call1stPartyFuncDefinedInFileCtor content) = prologify_Call1stPartyFuncDefinedInFile content
+prologify (CallMethodOfUntypedNamedParamCtor content) = prologify_CallMethodOfUntypedNamedParam content
+
+prologify_ParamResolvedType' :: Location -> String -> String
+prologify_ParamResolvedType' l fqn = printf "kb_param_has_resolved_type( %s, \'%s\' )." (locationify l) fqn
+
+prologify_ParamResolvedType :: ParamResolvedType -> String
+prologify_ParamResolvedType (ParamResolvedType (Param loc) (ResolvedType fqn)) = prologify_ParamResolvedType' loc (prologifyFqn fqn)
+
+prologify_CallMethodOfClass' :: Location -> String -> Location -> String
+prologify_CallMethodOfClass' call method klass = printf "kb_call_method_of_class( %s, \'%s\', %s )." (locationify call) method (locationify klass)
+
+prologify_CallMethodOfClass :: CallMethodOfClass -> String
+prologify_CallMethodOfClass (CallMethodOfClass (Call loc) (MethodName m) (Class c)) = prologify_CallMethodOfClass' loc m c
+
+prologify_ParamName' :: Location -> String -> String
+prologify_ParamName' l name = printf "kb_param_has_name( %s, \'%s\' )." (locationify l) name
+
+prologify_ParamName :: ParamName -> String
+prologify_ParamName (ParamName (Param loc) (Token.ParamName (Token.Named name _))) = prologify_ParamName' loc name
+
+prologify_ClassDef' :: Location -> String -> FilePath -> String
+prologify_ClassDef' l name f = printf "kb_class_def( %s, \'%s\', \'%s\' )." (locationify l) name f
+
+prologify_ClassDef :: ClassDef -> String
+prologify_ClassDef (ClassDef (Class loc) (Token.ClassName (Token.Named name _)) (ClassDefinedInFile f)) = prologify_ClassDef' loc name f
+
+prologify_FuncDef' :: Location -> String -> FilePath -> FilePath -> String
+prologify_FuncDef' l name f d = printf "kb_func_def( %s, \'%s\', \'%s\', \'%s\' )." (locationify l) name f d
+
+prologify_FuncDef :: FuncDef -> String
+prologify_FuncDef (FuncDef (Func loc) (Token.FuncName (Token.Named name _)) (FuncDefinedInFile f) (FuncDefinedInDir d)) = prologify_FuncDef' loc name f d
+
+unquote :: String -> String
+unquote = filter (/= '\'')
+
+prologify_ConstString' :: Location -> String -> String
+prologify_ConstString' l value = printf "kb_const_string( %s, \'%s\' )." (locationify l) (unquote value)
+
+prologify_ConstString :: ConstString -> String
+prologify_ConstString (ConstString (ConstStr loc) (Token.ConstStr value _)) = prologify_ConstString' loc value
+
+prologify_ConstInteger' :: Location -> Int -> String
+prologify_ConstInteger' l value = printf "kb_const_int( %s, %d )." (locationify l) value
+
+prologify_ConstInteger :: ConstInteger -> String
+prologify_ConstInteger (ConstInteger (ConstInt loc) (Token.ConstInt value _)) = prologify_ConstInteger' loc value
+
+prologify_CallResolved'' :: Location -> String -> Token.ClassName -> String
+prologify_CallResolved'' call m c = printf "kb_call_method_of_class( %s, %s, %s )." (locationify call) m (locationify (Token.getClassNameLocation c))
+
+prologify_CallResolved' :: Location -> Fqn.Fqn -> String
+prologify_CallResolved' call (Fqn.CallMethodOfClass _ m c) = prologify_CallResolved'' call m c 
+prologify_CallResolved' call fqn = printf "kb_call_resolved( %s, \'%s\' )." (locationify call) (prologifyFqn fqn)
+
+prologify_DataflowEdge :: DataflowEdge -> String
+prologify_DataflowEdge (DataflowEdge (From u) (To v)) = prologify_DataflowEdge' u v
+
+prologify_DataflowEdge' :: Location -> Location -> String
+prologify_DataflowEdge' u v = printf "kb_dataflow_edge( %s, %s )." (locationify u) (locationify v)
+
+prologify_CallResolved :: CallResolved -> String
+prologify_CallResolved (CallResolved (Call call) (Resolved fqn)) = prologify_CallResolved' call fqn
+
+prologify_ConstBoolTrue' :: Location -> String
+prologify_ConstBoolTrue' trueValue = printf "kb_class_name( %s, \'%s\' )." (locationify trueValue)
+
+prologify_ConstBoolTrue :: ConstBoolTrue -> String
+prologify_ConstBoolTrue (ConstBoolTrue trueValue) = prologify_ConstBoolTrue' trueValue
+
+prologify_ConstNull' :: Location -> String
+prologify_ConstNull' l = printf "kb_const_null( %s )." (locationify l)
+
+prologify_ConstNull :: ConstNull -> String
+prologify_ConstNull (ConstNull loc) = prologify_ConstNull' loc
+
+prologify_GatedReturn' :: Location -> Location -> String
+prologify_GatedReturn' c v = printf "kb_gated_return( %s, %s )." (locationify c) (locationify v)
+
+prologify_GatedReturn :: GatedReturn -> String
+prologify_GatedReturn (GatedReturn (Cond c) (ReturnedValue v)) = prologify_GatedReturn' c v
+
+prologify_Comparison' :: Location -> Location -> Location -> String -> String
+prologify_Comparison' c l r op = printf "kb_comparison( %s, %s, %s, %s )." (locationify c) (locationify l) (locationify r) op
+
+prologify_Comparison :: Comparison -> String
+prologify_Comparison (Comparison (Cond c) (Lhs l) (Rhs r) (ComparisonOp op)) = prologify_Comparison' c l r op
+
+prologify_CallableReturnsValue' :: Location -> Location -> String
+prologify_CallableReturnsValue' c v = printf "kb_callable_returns_value( %s, %s )." (locationify c) (locationify v)
+
+prologify_CallableReturnsValue :: CallableReturnsValue -> String
+prologify_CallableReturnsValue (CallableReturnsValue (Callable c) (ReturnedValue v)) = prologify_CallableReturnsValue' c v
+
+prologify_CallableReturnsWithoutValue' :: Location -> Location -> String
+prologify_CallableReturnsWithoutValue' c s = printf "kb_callable_returns_without_value( %s, %s )." (locationify c) (locationify s)
+
+prologify_CallableReturnsWithoutValue :: CallableReturnsWithoutValue -> String
+prologify_CallableReturnsWithoutValue (CallableReturnsWithoutValue (Callable c) s) = prologify_CallableReturnsWithoutValue' c s
+
+prologify_MethodOfClass' :: Location -> Location -> String
+prologify_MethodOfClass' m c = printf "kb_method_of_class( %s, %s )." (locationify m) (locationify c)
+
+prologify_MethodOfClass :: MethodOfClass -> String
+prologify_MethodOfClass (MethodOfClass (Method m) (Class c)) = prologify_MethodOfClass' m c
+
+prologify_ClassHas1stPartySuper' :: Location -> String -> FilePath -> String
+prologify_ClassHas1stPartySuper' c s f = printf "kb_class_has_1st_party_super( %s, \'%s\', \'%s\' )." (locationify c) s f
+ 
+prologify_ClassHas1stPartySuper :: ClassHas1stPartySuper -> String
+prologify_ClassHas1stPartySuper (ClassHas1stPartySuper (Class c) (Token.SuperName (Token.Named s _)) (SuperDefinedInFile f)) = prologify_ClassHas1stPartySuper' c s f
+
+prologify_ClassHas3rdPartySuper' :: Location -> String -> Fqn.Fqn -> String
+prologify_ClassHas3rdPartySuper' c s f = printf "kb_class_has_3rd_party_super( %s, \'%s\', \'%s\' )." (locationify c) s (prologifyFqn f)
+ 
+prologify_ClassHas3rdPartySuper :: ClassHas3rdPartySuper -> String
+prologify_ClassHas3rdPartySuper (ClassHas3rdPartySuper (Class c) (Token.SuperName (Token.Named s _)) (SuperQualifiedName f)) = prologify_ClassHas3rdPartySuper' c s f
+
+prologify_AssignValueToToplevelVarName :: AssignValueToToplevelVarName -> String
+prologify_AssignValueToToplevelVarName (AssignValueToToplevelVarName value varname) = prologify_AssignValueToToplevelVarName' value varname
+
+prologify_AssignValueToToplevelVarName' :: AssignedValue -> Token.VarName -> String
+prologify_AssignValueToToplevelVarName' (AssignedValue value) (Token.VarName (Token.Named varname l)) = prologify_AssignValueToToplevelVarName'' value varname (Location.filename l)
+
+prologify_AssignValueToToplevelVarName'' :: Location -> String -> FilePath -> String
+prologify_AssignValueToToplevelVarName'' value varname f = printf "kb_assign_value_to_toplevel_varname( %s, \'%s\', \'%s\', \'%s\')." (locationify value) varname f (takeDirectory f)
+
+prologify_Call1stPartyFuncDefinedInFile :: Call1stPartyFuncDefinedInFile -> String
+prologify_Call1stPartyFuncDefinedInFile (Call1stPartyFuncDefinedInFile call func f) = prologify_Call1stPartyFuncDefinedInFile' call func f
+
+prologify_Call1stPartyFuncDefinedInFile' :: Call -> FuncName -> FuncDefinedInFile -> String
+prologify_Call1stPartyFuncDefinedInFile' (Call call) (FuncName func) (FuncDefinedInFile f) = prologify_Call1stPartyFuncDefinedInFile'' call func f
+
+prologify_Call1stPartyFuncDefinedInFile'' :: Location -> String -> FilePath -> String
+prologify_Call1stPartyFuncDefinedInFile'' call func f = printf "kb_call_1st_party_func_defined_in_file( %s, \'%s\', \'%s\' )." (locationify call) func f
+
+prologify_Call1stPartyFuncDefinedInDir :: Call1stPartyFuncDefinedInDir -> String
+prologify_Call1stPartyFuncDefinedInDir (Call1stPartyFuncDefinedInDir call func d) = prologify_Call1stPartyFuncDefinedInDir' call func d
+
+prologify_Call1stPartyFuncDefinedInDir' :: Call -> FuncName -> FuncDefinedInDir -> String
+prologify_Call1stPartyFuncDefinedInDir' (Call call) (FuncName f) (FuncDefinedInDir d) = prologify_Call1stPartyFuncDefinedInDir'' call f d
+
+prologify_Call1stPartyFuncDefinedInDir'' :: Location -> String -> FilePath -> String
+prologify_Call1stPartyFuncDefinedInDir'' call f d = printf "kb_call_1st_party_func_defined_in_dir( %s, \'%s\', \'%s\' )." (locationify call) f d
+
+prologify_CallMethodOfUntypedNamedParam :: CallMethodOfUntypedNamedParam -> String
+prologify_CallMethodOfUntypedNamedParam (CallMethodOfUntypedNamedParam call method p) = prologify_CallMethodOfUntypedNamedParam' call method p
+
+prologify_CallMethodOfUntypedNamedParam' :: Call -> MethodName -> Token.ParamName -> String
+prologify_CallMethodOfUntypedNamedParam' (Call call) (MethodName m) (Token.ParamName (Token.Named _ p)) = prologify_CallMethodOfUntypedNamedParam'' call m p
+
+prologify_CallMethodOfUntypedNamedParam'' :: Location -> String -> Location -> String
+prologify_CallMethodOfUntypedNamedParam'' call m p = printf "kb_call_method_of_untyped_named_param( %s, \'%s\', %s )." (locationify call) m (locationify p)
+
+prologifyArgiForCall' :: Location -> Word -> Location -> String
+prologifyArgiForCall' a i c = printf "kb_arg_i_for_call( %s, %u, %s )." (locationify a) i (locationify c)
+
+prologifyArgiForCall :: ArgiForCall -> String
+prologifyArgiForCall (ArgiForCall (Arg a) (ArgIndex i) (Call c)) = prologifyArgiForCall' a i c
+
+prologify_ClassAnnotation' :: Location -> Location -> String
+prologify_ClassAnnotation' c a = printf "kb_class_has_annotation( %s, %s )." (locationify c) (locationify a)
+
+prologify_ClassAnnotation :: ClassAnnotation -> String
+prologify_ClassAnnotation (ClassAnnotation (Class c) (Annotation a)) = prologify_ClassAnnotation' c a
+
+prologify_KeywordArgForCall' ::  String -> Location -> Location -> String
+prologify_KeywordArgForCall' kw a c = printf "kb_keyword_arg_for_call( %s, %s, %s )." (locationify a) kw (locationify c)
+
+prologify_KeywordArgForCall :: KeywordArgForCall -> String
+prologify_KeywordArgForCall (KeywordArgForCall (Keyword kw) (Arg a) (Call c)) = prologify_KeywordArgForCall' kw a c
+
+prologify_CallableAnnotation' :: Location -> Location -> String
+prologify_CallableAnnotation' c a = printf "kb_callable_has_annotation( %s, %s )." (locationify c) (locationify a)
+
+prologify_CallableAnnotation :: CallableAnnotation -> String
+prologify_CallableAnnotation (CallableAnnotation (Callable c) (Annotation a)) = prologify_CallableAnnotation' c a
+
+prologify_CallableSourceBodyLength' :: Location -> Word -> String
+prologify_CallableSourceBodyLength' c n = printf "kb_callable_source_body_length( %s, %u )." (locationify c) n
+
+prologify_CallableSourceBodyLength :: CallableSourceBodyLength -> String
+prologify_CallableSourceBodyLength (CallableSourceBodyLength (Callable c) n) = prologify_CallableSourceBodyLength' c n
+
+prologify_ParamiOfCallable' :: Location -> Word -> Location -> String
+prologify_ParamiOfCallable' p i c = printf "kb_param_i_of_callable( %s, %u, %s )." (locationify p) i (locationify c)
+
+prologify_ParamiOfCallable :: ParamiOfCallable -> String
+prologify_ParamiOfCallable (ParamiOfCallable (Param p) (ParamIndex i) (Callable c)) = prologify_ParamiOfCallable' p i c
+
+prologify_CalledFrom' :: Location -> Location -> String
+prologify_CalledFrom' call callable = printf "kb_called_from( %s, %s )." (locationify call) (locationify callable)
+
+prologify_CalledFrom :: CalledFrom -> String
+prologify_CalledFrom (CalledFrom (Call call) (Callable callable)) = prologify_CalledFrom' call callable
+
+normalizeChar :: Char -> String
+normalizeChar '/' = "_slash_"
+normalizeChar '.' = "_dot_"
+normalizeChar '-' = "_dash_"
+normalizeChar '['  = "_lbrack_"
+normalizeChar ']'  = "_rbrack_"
+normalizeChar '('  = "_lparen_"
+normalizeChar ')'  = "_rparen_"
+normalizeChar c = [c]
+
+normalize :: FilePath -> FilePath
+normalize path = concatMap normalizeChar path
+
+prologifyFqn :: Fqn.Fqn -> String
+prologifyFqn (Fqn.ThirdPartyImport fqn) = prologifyThirdPartyImport fqn
+prologifyFqn (Fqn.FieldedAccess fqn fieldName) = prologifyFieldedAccess fqn fieldName
+prologifyFqn fqn = show fqn
+
+prologifyThirdPartyImport :: Fqn.ThirdPartyImportContent -> String
+prologifyThirdPartyImport (Fqn.ThirdPartyImportContent p [] Nothing _) = p
+prologifyThirdPartyImport (Fqn.ThirdPartyImportContent p [] (Just name) _) = p ++ "." ++ name
+prologifyThirdPartyImport (Fqn.ThirdPartyImportContent p rest Nothing _) = p ++ "." ++ List.intercalate "." rest
+prologifyThirdPartyImport (Fqn.ThirdPartyImportContent p rest (Just name) _) = p ++ "." ++ List.intercalate "." rest ++ "." ++ name
+
+prologifyFieldedAccess :: Fqn.Fqn -> Token.FieldName -> String
+prologifyFieldedAccess fqn (Token.FieldName (Token.Named fieldName _)) = (prologifyFqn fqn) ++ "." ++ fieldName
+
+locationify :: Location -> String
+locationify l = let
+    x = Location.lineStart l
+    y = Location.colStart l
+    z = Location.lineEnd l
+    w = Location.colEnd l
+    f = normalize (Location.filename l)
+    in printf "startloc_%u_%u_endloc_%u_%u_%s" x y z w f
+
+restoreloc :: String -> Maybe Location
+restoreloc s = case parseOnly locationParser (T.pack s) of { Right l -> Just l; _ -> Nothing; }
+
+locationParser :: Parser Location
+locationParser = do {
+
+    _ <- string "startloc_"; x <- decimal; _ <- char '_'; y <- decimal;
+    _ <- string "_endloc_" ; z <- decimal; _ <- char '_'; w <- decimal;
+    _ <- char '_'; fname <- takeText;
+
+    pure Location {
+        filename  = restoreFilename (T.unpack fname),
+        lineStart = x,
+        colStart = y,
+        lineEnd = z,
+        colEnd = w
+    }
+}
+
+data Rule = Rule { from :: Text, to :: Text }
+
+rules :: [ Rule ]
+rules =
+    [ Rule { from = "_slash_",  to = "/" }
+    , Rule { from = "_dot_",    to = "." }
+    , Rule { from = "_dash_",   to = "-" }
+    , Rule { from = "_lbrack_", to = "[" }
+    , Rule { from = "_rbrack_", to = "]" }
+    , Rule { from = "_lparen_", to = "(" }
+    , Rule { from = "_rparen_", to = ")" }
+    ]
+
+applyRule :: Rule -> Text -> Text
+applyRule Rule { from = f, to = t } = T.replace f t
+
+applyRuleStep :: Text -> Rule -> Text
+applyRuleStep acc r = applyRule r acc
+
+restore :: Text -> Text
+restore txt = List.foldl' applyRuleStep txt rules
+
+textToStringAdapter :: (Text -> Text) -> String -> String
+textToStringAdapter f = T.unpack . f . T.pack
+
+restoreFilename :: String -> String
 restoreFilename = textToStringAdapter restore
