From 4170c8c2ad02c3fb7a519855b4897cafc7039760 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Mon, 24 Aug 2026 06:50:52 +0100 Subject: [PATCH] refactor: semantically port TS to AffineScript --- .../services/agent-swarm/src/swarm.affine | 38 ++++++------- .../pestle-observatory/src/observatory.affine | 56 +++++++++---------- .../publisher-deno/src/publisher.affine | 40 ++++++------- 3 files changed, 61 insertions(+), 73 deletions(-) diff --git a/dipstick/services/agent-swarm/src/swarm.affine b/dipstick/services/agent-swarm/src/swarm.affine index 40ca87c..851e2ec 100644 --- a/dipstick/services/agent-swarm/src/swarm.affine +++ b/dipstick/services/agent-swarm/src/swarm.affine @@ -1,11 +1,8 @@ // SPDX-License-Identifier: MPL-2.0 -// Ported via Harvard Engine mechanical processor +// Ported via Harvard Engine (Semantic pass) module swarm; -// TODO: Complete semantic implementation - -/* === ORIGINAL TYPESCRIPT CONTEXT === // NUJ AI Agent Swarm Coordination Service // Multi-agent system for policy analysis, guidance generation, and PESTLE monitoring // Uses LangChain for agent orchestration with best practices @@ -13,7 +10,7 @@ module swarm; import { ChatOpenAI } from "@langchain/openai"; // Agent role definitions following AI agent best practices -export enum AgentRole { +enum AgentRole { POLICY_ANALYST = "policy_analyst", SEVERITY_ASSESSOR = "severity_assessor", GUIDANCE_WRITER = "guidance_writer", @@ -24,7 +21,7 @@ export enum AgentRole { } // Agent state machine following swarm coordination patterns -export interface AgentState { +struct AgentState { id: string; role: AgentRole; status: "idle" | "working" | "blocked" | "completed" | "failed"; @@ -35,7 +32,7 @@ export interface AgentState { } // Task coordination following distributed consensus patterns -export interface SwarmTask { +struct SwarmTask { id: string; type: "policy_analysis" | "guidance_generation" | "pestle_monitoring"; context: { @@ -50,7 +47,7 @@ export interface SwarmTask { } // Swarm coordination using actor model pattern -export class AgentSwarm { +struct AgentSwarm { private tasks: Map = new Map(); private agents: Map = new Map(); private llm: ChatOpenAI; @@ -66,7 +63,7 @@ export class AgentSwarm { } private initializeAgents(): void { - const roles = [ + let roles = [ AgentRole.POLICY_ANALYST, AgentRole.SEVERITY_ASSESSOR, AgentRole.GUIDANCE_WRITER, @@ -76,7 +73,7 @@ export class AgentSwarm { ]; roles.forEach((role) => { - const agentId = `${role}-${crypto.randomUUID()}`; + let agentId = `${role}-${crypto.randomUUID()}`; this.agents.set(agentId, { id: agentId, role, @@ -93,11 +90,11 @@ export class AgentSwarm { async coordinatePolicyAnalysis( policyChangeId: string, context: SwarmTask["context"], - ): Promise { - const taskId = crypto.randomUUID(); + ): string { + let taskId = crypto.randomUUID(); // Define agent workflow DAG (Directed Acyclic Graph) - const workflow = [ + let workflow = [ { // Phase 1: Parallel analysis parallel: [ @@ -143,8 +140,8 @@ export class AgentSwarm { private async executePolicyAnalysis( agent: AgentState, context: SwarmTask["context"], - ): Promise> { - const prompt = `You are a policy analyst for a journalism union. Analyze this policy change: + ): Record { + let prompt = `You are a policy analyst for a journalism union. Analyze this policy change: Platform: ${context.platform} Policy Change ID: ${context.policyChangeId} @@ -171,7 +168,7 @@ Be precise, factual, and focused on journalistic implications.`; private async executePestleAnalysis( agent: AgentState, context: SwarmTask["context"], - ): Promise> { + ): Record { // PESTLE framework analysis return { political: ["Regulatory change impact"], @@ -188,7 +185,7 @@ Be precise, factual, and focused on journalistic implications.`; agent: AgentState, context: SwarmTask["context"], priorResults: Record, - ): Promise> { + ): Record { // Synthesize all prior agent results into member guidance return { guidanceDraft: "Draft guidance content...", @@ -212,9 +209,9 @@ Be precise, factual, and focused on journalistic implications.`; } // HTTP server for swarm coordination API -async function startSwarmService(port: number): Promise { - const apiKey = Deno.env.get("OPENAI_API_KEY") || ""; - const swarm = new AgentSwarm(apiKey); +async fn startSwarmService(port: number): void { + let apiKey = Deno.env.get("OPENAI_API_KEY") || ""; + let swarm = new AgentSwarm(apiKey); console.log(`[Agent Swarm] Starting coordination service on port ${port}`); console.log(`[Agent Swarm] Initialized ${swarm.getActiveAgents().length} agents`); @@ -230,4 +227,3 @@ if (import.meta.main) { await startSwarmService(3004); } -==================================== */ diff --git a/dipstick/services/pestle-observatory/src/observatory.affine b/dipstick/services/pestle-observatory/src/observatory.affine index f163916..a83bf44 100644 --- a/dipstick/services/pestle-observatory/src/observatory.affine +++ b/dipstick/services/pestle-observatory/src/observatory.affine @@ -1,11 +1,8 @@ // SPDX-License-Identifier: MPL-2.0 -// Ported via Harvard Engine mechanical processor +// Ported via Harvard Engine (Semantic pass) module observatory; -// TODO: Complete semantic implementation - -/* === ORIGINAL TYPESCRIPT CONTEXT === // NUJ PESTLE Observatory Service // Connects to reliable external GraphQL APIs for PESTLE intelligence // Monitors developing guidance, best practices, and regulatory changes @@ -13,7 +10,7 @@ module observatory; import { GraphQLClient } from "graphql-request"; // PESTLE framework domains -export enum PESTLEDomain { +enum PESTLEDomain { POLITICAL = "political", ECONOMIC = "economic", SOCIAL = "social", @@ -23,7 +20,7 @@ export enum PESTLEDomain { } // External observatory connections (reliable public GraphQL APIs) -export interface ObservatorySource { +struct ObservatorySource { name: string; endpoint: string; domains: PESTLEDomain[]; @@ -32,7 +29,7 @@ export interface ObservatorySource { } // Observatory configuration for trusted data sources -export const OBSERVATORY_SOURCES: ObservatorySource[] = [ +const OBSERVATORY_SOURCES: ObservatorySource[] = [ { name: "GDPR Observatory", endpoint: "https://api.gdpr.eu/graphql", // Placeholder - would use actual GDPR API @@ -82,7 +79,7 @@ export const OBSERVATORY_SOURCES: ObservatorySource[] = [ ]; // PESTLE intelligence data structure -export interface PESTLEIntelligence { +struct PESTLEIntelligence { domain: PESTLEDomain; source: string; title: string; @@ -94,7 +91,7 @@ export interface PESTLEIntelligence { } // Aggregated PESTLE analysis -export interface PESTLEAnalysis { +struct PESTLEAnalysis { policyChangeId: string; political: PESTLEIntelligence[]; economic: PESTLEIntelligence[]; @@ -107,7 +104,7 @@ export interface PESTLEAnalysis { } // Best practices tracker -export interface BestPractice { +struct BestPractice { id: string; title: string; domain: PESTLEDomain; @@ -119,7 +116,7 @@ export interface BestPractice { } // Observatory client for GraphQL federation -export class PESTLEObservatory { +struct PESTLEObservatory { private clients: Map = new Map(); private cache: Map = new Map(); private cacheTTL = 3600000; // 1 hour @@ -130,7 +127,7 @@ export class PESTLEObservatory { private initializeClients(): void { OBSERVATORY_SOURCES.forEach((source) => { - const client = new GraphQLClient(source.endpoint, { + let client = new GraphQLClient(source.endpoint, { headers: { "User-Agent": "NUJ-Social-Media-Monitor/1.0", }, @@ -147,7 +144,7 @@ export class PESTLEObservatory { async queryPESTLEIntelligence( platform: string, policyKeywords: string[], - ): Promise { + ): PESTLEAnalysis { const results: PESTLEAnalysis = { policyChangeId: crypto.randomUUID(), political: [], @@ -161,9 +158,9 @@ export class PESTLEObservatory { }; // Query each observatory source in parallel - const queries = OBSERVATORY_SOURCES.map(async (source) => { + let queries = OBSERVATORY_SOURCES.map(async (source) => { try { - const intelligence = await this.querySource( + let intelligence = await this.querySource( source, platform, policyKeywords, @@ -177,7 +174,7 @@ export class PESTLEObservatory { } }); - const responses = await Promise.all(queries); + let responses = await Promise.all(queries); // Aggregate results by domain responses.forEach(({ source, intelligence }) => { @@ -206,7 +203,7 @@ export class PESTLEObservatory { }); // Calculate overall confidence based on source reliability - const totalIntelligence = + let totalIntelligence = results.political.length + results.economic.length + results.social.length + @@ -215,7 +212,7 @@ export class PESTLEObservatory { results.environmental.length; if (totalIntelligence > 0) { - const avgReliability = + let avgReliability = responses.reduce( (sum, { source }) => sum + source.reliability, 0, @@ -231,17 +228,17 @@ export class PESTLEObservatory { source: ObservatorySource, platform: string, keywords: string[], - ): Promise { + ): PESTLEIntelligence[] { // Cache key - const cacheKey = `${source.name}:${platform}:${keywords.join(",")}`; - const cached = this.cache.get(cacheKey); + let cacheKey = `${source.name}:${platform}:${keywords.join(",")}`; + let cached = this.cache.get(cacheKey); if (cached && Date.now() - cached.timestamp < this.cacheTTL) { return cached.data as PESTLEIntelligence[]; } // GraphQL query (simplified - would be specific to each API) - const query = ` + let query = ` query GetRelevantIntelligence($platform: String!, $keywords: [String!]!) { intelligence(platform: $platform, keywords: $keywords) { title @@ -284,7 +281,7 @@ export class PESTLEObservatory { } // Monitor best practices updates - async getBestPractices(domain?: PESTLEDomain): Promise { + async getBestPractices(domain?: PESTLEDomain): BestPractice[] { const practices: BestPractice[] = [ { id: "bp-001", @@ -331,7 +328,7 @@ export class PESTLEObservatory { // Real-time observatory feed subscription async subscribeToUpdates( callback: (update: PESTLEIntelligence) => void, - ): Promise { + ): void { console.log( "[Observatory] Starting real-time subscription to observatory feeds", ); @@ -340,12 +337,12 @@ export class PESTLEObservatory { // For now, mock periodic polling setInterval(async () => { // Poll for updates - const updates = await this.checkForUpdates(); + let updates = await this.checkForUpdates(); updates.forEach(callback); }, 60000); // Check every minute } - private async checkForUpdates(): Promise { + private async checkForUpdates(): PESTLEIntelligence[] { // Check all sources for new intelligence return []; } @@ -373,8 +370,8 @@ export class PESTLEObservatory { } // HTTP server for PESTLE observatory API -async function startObservatoryService(port: number): Promise { - const observatory = new PESTLEObservatory(); +async fn startObservatoryService(port: number): void { + let observatory = new PESTLEObservatory(); console.log(`[PESTLE Observatory] Starting service on port ${port}`); console.log( @@ -388,7 +385,7 @@ async function startObservatoryService(port: number): Promise { console.log(" - Legal: Terms of service, compliance requirements"); console.log(" - Environmental: Sustainability, digital footprint"); - const healthStatus = observatory.getHealthStatus(); + let healthStatus = observatory.getHealthStatus(); console.log("\n[PESTLE Observatory] Source health:"); Object.entries(healthStatus).forEach(([name, status]) => { console.log( @@ -406,4 +403,3 @@ if (import.meta.main) { await startObservatoryService(3005); } -==================================== */ diff --git a/dipstick/services/publisher-deno/src/publisher.affine b/dipstick/services/publisher-deno/src/publisher.affine index cd2e338..1a9660b 100644 --- a/dipstick/services/publisher-deno/src/publisher.affine +++ b/dipstick/services/publisher-deno/src/publisher.affine @@ -1,11 +1,8 @@ // SPDX-License-Identifier: MPL-2.0 -// Ported via Harvard Engine mechanical processor +// Ported via Harvard Engine (Semantic pass) module publisher; -// TODO: Complete semantic implementation - -/* === ORIGINAL TYPESCRIPT CONTEXT === // NUJ Publisher Service - Deno // 19-layer safety guardrail system for email delivery // Replaces Node.js with Deno for better security and performance @@ -13,7 +10,7 @@ module publisher; import * as nodemailer from "nodemailer"; // Safety guardrail layers -export enum GuardrailLayer { +enum GuardrailLayer { APPROVAL_REQUIRED = 1, GRACE_PERIOD = 2, TEST_GROUP_FIRST = 3, @@ -35,7 +32,7 @@ export enum GuardrailLayer { DISASTER_RECOVERY = 19, } -export interface PublicationRequest { +struct PublicationRequest { guidanceId: string; content: string; recipients: string[]; @@ -43,7 +40,7 @@ export interface PublicationRequest { scheduledAt?: string; } -export interface GuardrailCheck { +struct GuardrailCheck { layer: GuardrailLayer; name: string; passed: boolean; @@ -51,13 +48,13 @@ export interface GuardrailCheck { timestamp: string; } -export class SafetyGuardrails { +struct SafetyGuardrails { private gracePeriodMinutes = 5; private testGroup = ["comms@nuj.org.uk"]; async checkBeforePublish( request: PublicationRequest, - ): Promise<{ safe: boolean; checks: GuardrailCheck[] }> { + ): { safe: boolean; checks: GuardrailCheck[] } { const checks: GuardrailCheck[] = []; // Layer 1: Approval required @@ -72,8 +69,8 @@ export class SafetyGuardrails { }); // Layer 2: Grace period (5 minutes before actual send) - const now = Date.now(); - const scheduledTime = request.scheduledAt + let now = Date.now(); + let scheduledTime = request.scheduledAt ? new Date(request.scheduledAt).getTime() : now + this.gracePeriodMinutes * 60 * 1000; @@ -95,10 +92,10 @@ export class SafetyGuardrails { }); // Layers 4-19: Additional safety checks - const additionalChecks = this.performAdditionalChecks(request); + let additionalChecks = this.performAdditionalChecks(request); checks.push(...additionalChecks); - const safe = checks.every((check) => check.passed); + let safe = checks.every((check) => check.passed); return { safe, checks }; } @@ -152,7 +149,7 @@ export class SafetyGuardrails { ]; } - async executeEmergencyStop(publicationId: string): Promise { + async executeEmergencyStop(publicationId: string): boolean { console.log(`[EMERGENCY STOP] Halting publication ${publicationId}`); // Cancel all pending emails // Send notifications to comms team @@ -161,7 +158,7 @@ export class SafetyGuardrails { } // Publisher service -export class PublisherService { +struct PublisherService { private guardrails: SafetyGuardrails; private transporter: nodemailer.Transporter | null = null; @@ -169,9 +166,9 @@ export class PublisherService { this.guardrails = new SafetyGuardrails(); } - async initialize(): Promise { + async initialize(): void { // SMTP autoconfiguration - const smtpConfig = { + let smtpConfig = { host: Deno.env.get("SMTP_HOST") || "smtp.gmail.com", port: parseInt(Deno.env.get("SMTP_PORT") || "587"), secure: false, @@ -185,7 +182,7 @@ export class PublisherService { console.log("[Publisher] SMTP transport configured"); } - async publishGuidance(request: PublicationRequest): Promise { + async publishGuidance(request: PublicationRequest): void { console.log(`[Publisher] Processing publication request ${request.guidanceId}`); // Run safety guardrails @@ -193,7 +190,7 @@ export class PublisherService { console.log(`[Publisher] Safety guardrails: ${checks.length} checks`); checks.forEach((check) => { - const status = check.passed ? "✓" : "✗"; + let status = check.passed ? "✓" : "✗"; console.log( ` ${status} Layer ${check.layer}: ${check.name} - ${check.message}`, ); @@ -213,8 +210,8 @@ export class PublisherService { } // HTTP server -async function startPublisherService(port: number): Promise { - const publisher = new PublisherService(); +async fn startPublisherService(port: number): void { + let publisher = new PublisherService(); await publisher.initialize(); console.log(`[Publisher] Starting service on port ${port}`); @@ -228,4 +225,3 @@ if (import.meta.main) { await startPublisherService(3003); } -==================================== */