Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | 6x 8x 8x 3x 8x 8x 5x 5x 5x 5x 5x 5x 1x 8x 8x 8x 3x 3x 3x | /**
* @module mcp-client/methods/votes
* @description Voting record / votering domain methods for the MCP client.
*
* @author Hack23 AB
* @license Apache-2.0
*/
import type { MCPTransportClient } from '../transport/jsonrpc.js';
import type {
FetchVotingFilters,
FetchVotingGroupFilters,
MCPSearchResult,
MCPStructuredSignal,
MCPProvenance,
} from '../../types/mcp.js';
import { attachCoverageMetadata, buildMcpProvenance } from '../coverage.js';
import { previousRiksmote } from '../riksmote/helpers.js';
export async function fetchVotingRecords(
transport: MCPTransportClient,
filters: FetchVotingFilters,
): Promise<unknown[]> {
return (await fetchVotingRecordsWithDiagnostics(transport, filters)).items;
}
export async function fetchVotingRecordsWithDiagnostics(
transport: MCPTransportClient,
filters: FetchVotingFilters,
): Promise<MCPSearchResult<Record<string, unknown>> & { signal?: MCPStructuredSignal }> {
const response = await transport.request(
'search_voteringar',
filters as unknown as Record<string, unknown>,
);
const items = ((response['votes'] ?? response['voteringar'] ?? []) as Record<string, unknown>[])
.map((vote) => ({ ...vote }));
const resultCount = items.length;
let signal: MCPStructuredSignal | undefined;
if (resultCount === 0 && typeof filters.rm === 'string') {
const comparisonRm = previousRiksmote(filters.rm);
Eif (comparisonRm) {
try {
const comparisonResponse = await transport.request(
'search_voteringar',
{ ...(filters as Record<string, unknown>), rm: comparisonRm },
);
const comparisonCount = (
(comparisonResponse['votes'] ?? comparisonResponse['voteringar'] ?? []) as unknown[]
).length;
if (comparisonCount > 0) {
signal = {
code: 'MCP_INDEXING_LAG',
severity: 'warning',
message: `search_voteringar returned 0 rows for ${filters.rm} while ${comparisonRm} still returns ${comparisonCount}; this may indicate indexing lag or pending vote availability, so queue an exact-query retry for the next run.`,
tool: 'search_voteringar',
query: { ...(filters as Record<string, unknown>) },
observedResultCount: resultCount,
comparisonRm,
comparisonResultCount: comparisonCount,
action: 'retry_queue',
};
}
} catch {
// Best-effort comparison only; the primary zero-result response still stands.
}
}
}
const coverageState = resultCount === 0 ? 'search_empty' : 'metadata_only';
const provenance: MCPProvenance = buildMcpProvenance({
endpoint: transport.baseURL,
tool: 'search_voteringar',
query: filters as Record<string, unknown>,
resultCount,
coverageState,
signals: signal ? [signal] : undefined,
});
return {
items: items.map((vote) => attachCoverageMetadata(vote, provenance)),
query: { ...(filters as Record<string, unknown>) },
resultCount,
coverageState,
provenance,
...(signal ? { signal } : {}),
};
}
export async function fetchVotingGroup(
transport: MCPTransportClient,
params: FetchVotingGroupFilters = {},
): Promise<unknown[]> {
const response = await transport.request(
'get_voting_group',
params as unknown as Record<string, unknown>,
);
return (response['groups'] ?? response['votes'] ?? []) as unknown[];
}
|