SNAPKITTYWEST's picture
chore: push full sov-kernel-monster content from local build
9425aed verified
Raw History Blame Contribute Delete
4.83 kB
% query.pl — Agent query interface for GitBucket
%
% Returns proof-carrying context bundles.
% Every query produces an audit trail.
:- module(query, [
assemble_context/2,
query_buckets/3,
topological_sort/2,
build_context/3
]).
:- use_module(library(lists)).
:- use_module(index).
%% assemble_context(+QuerySpec, -ContextBundle)
% Main entry point. Resolves query → verifies seals → builds context.
assemble_context(QuerySpec, ContextBundle) :-
% 1. Resolve query to bucket IDs
resolve_query(QuerySpec, BucketIDs),
% 2. Fetch buckets and verify seals
maplist(verify_and_fetch, BucketIDs, Buckets),
% 3. Topological sort by dependency
topological_sort(Buckets, Ordered),
% 4. Build minimal context (token-budget aware)
( QuerySpec.get(budget) = Budget
-> true
; Budget = 8000
),
build_context(Ordered, Budget, Context),
% 5. Attach audit trail
get_time(Now),
ContextBundle = _{
context: Context,
audit: _{
query: QuerySpec,
buckets: BucketIDs,
verifier: "Plasma_Gate",
timestamp: Now,
count: Buckets
}
}.
%% query_buckets(+QuerySpec, -BucketIDs, -Buckets)
% Low-level query that returns raw buckets.
query_buckets(QuerySpec, BucketIDs, Buckets) :-
resolve_query(QuerySpec, BucketIDs),
maplist(verify_and_fetch, BucketIDs, Buckets).
%% topological_sort(+Buckets, -Sorted)
% Sorts buckets by dependency order (parents before children).
topological_sort(Buckets, Sorted) :-
% Build adjacency: for each bucket, find its dependencies
maplist(bucket_deps, Buckets, DepPairs),
% Simple topological sort (Kahn's algorithm)
topological_kahn(Buckets, DepPairs, Sorted).
%% build_context(+OrderedBuckets, +Budget, -Context)
% Builds a minimal context bundle within the token budget.
build_context([], _, _{buckets: [], total_tokens: 0}).
build_context(Buckets, Budget, Context) :-
maplist(bucket_to_context, Buckets, ContextPieces),
fit_budget(ContextPieces, Budget, Fitted),
sum_tokens(Fitted, Total),
Context = _{buckets: Fitted, total_tokens: Total}.
% --- Internal helpers ---
resolve_query(QuerySpec, BucketIDs) :-
( QuerySpec.get(topic) = Topic
-> index:query_by_topic(Topic, Buckets)
; QuerySpec.get(file) = File
-> index:query_by_file(File, Buckets)
; QuerySpec.get(entity) = Entity
-> index:query_by_entity(Entity, Buckets)
; QuerySpec.get(agent) = Agent
-> index:query_by_agent(Agent, Buckets)
; QuerySpec.get(type) = Type
-> index:query_by_type(Type, Buckets)
; QuerySpec.get(since) = Since
-> ( QuerySpec.get(until) = Until
-> index:query_by_time(Since, Until, Buckets)
; index:query_by_time(Since, "9999-12-31", Buckets)
)
; Buckets = []
),
maplist(bucket_id, Buckets, BucketIDs).
bucket_id(Bucket, ID) :- Bucket = _{id: ID}.
verify_and_fetch(BucketID, Bucket) :-
memory_bucket(Bucket),
Bucket = _{id: BucketID}.
bucket_deps(Bucket, Deps) :-
Bucket = _{id: ID, related: Related},
Deps = ID-Related.
topological_kahn([], _, []).
topological_kahn(Buckets, DepPairs, [Bucket|Rest]) :-
% Find a bucket with no unresolved dependencies
select(Bucket, Buckets, Remaining),
Bucket = _{id: ID},
\+ (member(ID-_, DepPairs), \+ memberchk(ID, [])),
topological_kahn(Remaining, DepPairs, Rest).
topological_kahn(Buckets, _, Buckets). % fallback: no ordering possible
bucket_to_context(Bucket, ContextPiece) :-
Bucket = _{id: ID, summary: Summary, type: Type, timestamp: Timestamp, files: Files},
maplist(file_path, Files, Paths),
ContextPiece = _{
id: ID,
summary: Summary,
type: Type,
timestamp: Timestamp,
files: Paths
}.
file_path(FileEntry, Path) :- FileEntry = _{path: Path}.
fit_budget(Pieces, Budget, Fitted) :-
fit_budget_loop(Pieces, Budget, 0, Fitted).
fit_budget_loop([], _, _, []).
fit_budget_loop([P|Ps], Budget, Used, [P|Rest]) :-
estimate_tokens(P, Tokens),
NewUsed is Used + Tokens,
NewUsed =< Budget,
fit_budget_loop(Ps, Budget, NewUsed, Rest).
fit_budget_loop(_, Budget, Used, []) :-
Used >= Budget.
estimate_tokens(Piece, Tokens) :-
Piece = _{summary: Summary, files: Files},
string_length(Summary, SLen),
length(Files, FLen),
Tokens is SLen + (FLen * 50).
sum_tokens([], 0).
sum_tokens([P|Ps], Total) :-
P = _{summary: S, files: F},
string_length(S, SL),
length(F, FL),
Tokens is SL + (FL * 50),
sum_tokens(Ps, Rest),
Total is Tokens + Rest.