Skip to content

[duplicate-code] Duplicate Code Pattern: WASM Guard Function Dispatch Boilerplate #2826

@github-actions

Description

@github-actions

Part of duplicate code analysis: #2825

Summary

LabelAgent, LabelResource, and LabelResponse in internal/guard/wasm.go each follow the same ~12-line preamble before doing any function-specific work. This preamble is copy-pasted three times and will drift silently if one copy is updated but the others are not.

Duplication Details

Pattern: WASM guard function dispatch preamble

  • Severity: Medium
  • Occurrences: 3 functions
  • Locations:
    • internal/guard/wasm.goLabelAgent (~lines 604–620)
    • internal/guard/wasm.goLabelResource (~lines 673–690)
    • internal/guard/wasm.goLabelResponse (~lines 715–733)

Repeated block (simplified):

// Serialize access to the WASM module
g.mu.Lock()
defer g.mu.Unlock()

// Update backend caller for this request
g.backend = backend

// Build input map
input := map[string]interface{}{...}
if caps != nil {
    input["capabilities"] = caps
}

// Marshal input
inputJSON, err := json.Marshal(input)
if err != nil {
    return ..., fmt.Errorf("failed to marshal input: %w", err)
}
logWasm.Printf("... input JSON (%d bytes): %s", len(inputJSON), string(inputJSON))

// Call WASM function
resultJSON, err := g.callWasmFunction(ctx, "<func_name>", inputJSON)
if err != nil {
    return ..., err
}

Each function deviates only in the input map keys and the response-parsing step, making the shared preamble a clear candidate for extraction.

Impact Analysis

  • Maintainability: A change to the locking strategy, backend update, or caps injection must be applied identically in three places.
  • Bug Risk: Medium — a future change that adds, say, a timeout or tracing span to the preamble will likely miss one of the three functions.
  • Code Bloat: ~36 extra lines of duplicate preamble.

Refactoring Recommendations

  1. Extract callWasmGuardFunction helper

    // callWasmGuardFunction serialises WASM access, updates the backend reference,
    // marshals inputData, calls the named WASM function, and returns the raw result.
    func (g *WasmGuard) callWasmGuardFunction(
        ctx context.Context,
        funcName string,
        backend BackendCaller,
        inputData map[string]interface{},
    ) ([]byte, error) {
        g.mu.Lock()
        defer g.mu.Unlock()
        g.backend = backend
        inputJSON, err := json.Marshal(inputData)
        if err != nil {
            return nil, fmt.Errorf("failed to marshal %s input: %w", funcName, err)
        }
        logWasm.Printf("%s input JSON (%d bytes): %s", funcName, len(inputJSON), string(inputJSON))
        return g.callWasmFunction(ctx, funcName, inputJSON)
    }
  2. Each public method then becomes:

    • Build the function-specific input map
    • Call g.callWasmGuardFunction(ctx, "label_xxx", backend, input)
    • Parse the returned resultJSON
    • Estimated effort: ~1 hour; risk: low (pure refactor, no logic change)

Implementation Checklist

  • Review all three function preambles to confirm they are structurally identical
  • Extract callWasmGuardFunction helper
  • Update LabelAgent, LabelResource, LabelResponse to use the helper
  • Update tests to confirm no behavioural change
  • Verify no functionality broken

Parent Issue

See parent analysis report: #2825
Related to #2825

Generated by Duplicate Code Detector ·

  • expires on Apr 6, 2026, 6:10 AM UTC

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions