{
  "apiVersion": "intentspec.io/v1alpha1",
  "kind": "IntentSpec",
  "metadata": {
    "id": "01J0R2W9K9G9N5W1QZ8YQ1M8P3",
    "createdAt": "2026-02-19T10:00:00Z",
    "createdBy": {
      "type": "user",
      "id": "alice",
      "displayName": "Alice Zhang"
    },
    "target": {
      "repo": {
        "type": "git",
        "locator": "git@company.internal:backend/user-service.git"
      },
      "baseRef": "main",
      "labels": {
        "ticket": "US-4521",
        "team": "backend"
      }
    }
  },
  "intent": {
    "summary": "Fix null pointer dereference causing HTTP 500 in handleRequest",
    "problemStatement": "Production monitoring shows that when the request body is missing the `userId` field, `handleRequest` in `src/handler.ts` (line 47) throws TypeError: Cannot read properties of undefined, resulting in HTTP 500 responses and alerts. Expected behaviour: return HTTP 400 Bad Request with a diagnostic error code. Related Sentry event: SENTRY-8821.",
    "changeType": "bugfix",
    "objectives": [
      "Validate the presence of userId at the handleRequest entry point; return HTTP 400 with error code ERR_MISSING_USER_ID when absent",
      "Add at least 2 unit test cases covering missing and invalid userId scenarios"
    ],
    "inScope": [
      "Input validation logic in src/handler.ts",
      "Corresponding test cases in test/handler.test.ts"
    ],
    "outOfScope": [
      "Do not introduce any new dependencies",
      "Do not change the API response structure (existing field semantics unchanged)",
      "Do not modify authentication or authorisation logic"
    ],
    "touchHints": {
      "files": [
        "src/handler.ts",
        "test/handler.test.ts"
      ],
      "symbols": [
        "handleRequest",
        "validateRequest"
      ],
      "apis": []
    }
  },
  "acceptance": {
    "successCriteria": [
      "Missing userId returns HTTP 400 with body containing code: ERR_MISSING_USER_ID",
      "Invalid userId (non-string type) also returns HTTP 400",
      "New test cases pass in CI",
      "No regression in existing test cases"
    ],
    "verificationPlan": {
      "fastChecks": [
        {
          "id": "typecheck",
          "kind": "command",
          "command": "npx tsc --noEmit",
          "timeoutSeconds": 120,
          "expectedExitCode": 0,
          "required": true,
          "artifactsProduced": []
        },
        {
          "id": "unit-test",
          "kind": "command",
          "command": "npm test -- --testPathPattern=handler",
          "timeoutSeconds": 300,
          "expectedExitCode": 0,
          "required": true,
          "artifactsProduced": [
            "test-log"
          ]
        },
        {
          "id": "lint",
          "kind": "command",
          "command": "npm run lint",
          "timeoutSeconds": 60,
          "expectedExitCode": 0,
          "required": true,
          "artifactsProduced": []
        }
      ],
      "integrationChecks": [],
      "securityChecks": [],
      "releaseChecks": []
    },
    "qualityGates": {
      "requireNewTestsWhenBugfix": true,
      "maxAllowedRegression": "none"
    }
  },
  "constraints": {
    "security": {
      "networkPolicy": "deny",
      "dependencyPolicy": "no-new",
      "cryptoPolicy": ""
    },
    "privacy": {
      "dataClassesAllowed": [
        "public"
      ],
      "redactionRequired": false,
      "retentionDays": 7
    },
    "licensing": {
      "allowedSpdx": [],
      "forbidNewLicenses": false
    },
    "platform": {
      "languageRuntime": "node20",
      "supportedOS": [
        "linux"
      ]
    },
    "resources": {
      "maxWallClockSeconds": 1800,
      "maxCostUnits": 0
    }
  },
  "risk": {
    "level": "low",
    "rationale": "Modifies only the input validation logic in a single file. No business logic changes, no new dependencies, no API semantic changes. Failure mode is confined to the same error path and does not affect normal request handling.",
    "factors": [
      "no-new-deps",
      "single-file",
      "input-validation-only"
    ],
    "humanInLoop": {
      "required": false,
      "minApprovers": 0
    }
  },
  "evidence": {
    "strategy": "repo-first",
    "trustTiers": [
      "repo",
      "vendor-doc"
    ],
    "domainAllowlistMode": "allowlist-only",
    "allowedDomains": [
      "nodejs.org",
      "www.typescriptlang.org"
    ],
    "blockedDomains": [],
    "minCitationsPerDecision": 0
  },
  "security": {
    "toolAcl": {
      "allow": [
        {
          "tool": "workspace.fs",
          "actions": [
            "read",
            "write"
          ],
          "constraints": {
            "writeRoots": [
              "./src",
              "./test"
            ],
            "maxWriteBytes": 51200
          }
        },
        {
          "tool": "workspace.command",
          "actions": [
            "execute"
          ],
          "constraints": {
            "allowCommands": [
              "npx tsc --noEmit",
              "npm test",
              "npm run lint"
            ],
            "maxOutputBytes": 1048576
          }
        },
        {
          "tool": "workspace.search",
          "actions": [
            "search"
          ],
          "constraints": {}
        }
      ],
      "deny": []
    },
    "secrets": {
      "policy": "deny-all",
      "allowedScopes": []
    },
    "promptInjection": {
      "treatRetrievedContentAsUntrusted": true,
      "enforceOutputSchema": true,
      "disallowInstructionFromEvidence": true
    },
    "outputHandling": {
      "encodingPolicy": "contextual-escape",
      "noDirectEval": true
    }
  },
  "execution": {
    "retry": {
      "maxRetries": 3,
      "backoffSeconds": 5
    },
    "replan": {
      "triggers": [
        "repeated-test-fail",
        "evidence-conflict"
      ]
    },
    "concurrency": {
      "maxParallelTasks": 2
    }
  },
  "artifacts": {
    "required": [
      {
        "name": "patchset",
        "stage": "per-task",
        "required": true,
        "format": "git-diff"
      },
      {
        "name": "test-log",
        "stage": "per-task",
        "required": true,
        "format": "text"
      }
    ],
    "retention": {
      "days": 7
    }
  },
  "provenance": {
    "requireSlsaProvenance": false,
    "requireSbom": false,
    "transparencyLog": {
      "mode": "none"
    },
    "bindings": {
      "embedIntentSpecDigest": true,
      "embedEvidenceDigests": false
    }
  },
  "lifecycle": {
    "schemaVersion": "1.0.0",
    "status": "active",
    "changeLog": []
  },
  "libra": {
    "objectStore": {
      "backend": "git-native",
      "blobRetentionStrategy": "ref-anchoring",
      "aiRefPrefix": "refs/ai/"
    },
    "contextPipeline": {
      "maxFrames": 32,
      "seedFrameKind": "IntentAnalysis",
      "checkpointOnReplan": false
    },
    "planGeneration": {
      "decompositionMode": "per-objective",
      "conflictResolution": "force-serial",
      "gateTaskPerStage": false
    },
    "runPolicy": {
      "patchsetFormat": "GitDiff",
      "snapshotOnRunStart": true,
      "metricsSchema": {
        "wall_clock_seconds": {
          "type": "integer"
        },
        "tokens_used": {
          "type": "integer"
        }
      }
    },
    "actorMapping": {
      "orchestratorActorId": "libra-orchestrator",
      "coderActorId": "libra-coder",
      "reviewerActorId": "libra-reviewer"
    },
    "decisionPolicy": {
      "abandonOnSecurityGateFail": true,
      "checkpointBeforeReplan": false,
      "rollbackOnProvenanceFail": false
    }
  },
  "extensions": {}
}
