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.go – LabelAgent (~lines 604–620)
internal/guard/wasm.go – LabelResource (~lines 673–690)
internal/guard/wasm.go – LabelResponse (~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
-
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)
}
-
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
Parent Issue
See parent analysis report: #2825
Related to #2825
Generated by Duplicate Code Detector · ◷
Part of duplicate code analysis: #2825
Summary
LabelAgent,LabelResource, andLabelResponseininternal/guard/wasm.goeach 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
internal/guard/wasm.go–LabelAgent(~lines 604–620)internal/guard/wasm.go–LabelResource(~lines 673–690)internal/guard/wasm.go–LabelResponse(~lines 715–733)Repeated block (simplified):
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
capsinjection must be applied identically in three places.Refactoring Recommendations
Extract
callWasmGuardFunctionhelperEach public method then becomes:
inputmapg.callWasmGuardFunction(ctx, "label_xxx", backend, input)resultJSONImplementation Checklist
callWasmGuardFunctionhelperLabelAgent,LabelResource,LabelResponseto use the helperParent Issue
See parent analysis report: #2825
Related to #2825