diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index d033ad4..9564c19 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -1,43 +1,9 @@ # Roadmap: CAS Reference Product -## Phase 1: Public v0.1 Reference Application +## Archived Milestones -**Goal:** Deliver a locally runnable, cloud-ready reference workload without deploying Azure resources. +- [x] [v0.1 Reference Application](milestones/v0.1-ROADMAP.md) — Delivered a locally runnable, cloud-ready reference workload without deploying Azure resources. -**Requirements:** API-01, AGENT-01, ID-01, CONTRACT-01, OBS-01, OPS-01, PLAT-01, QUAL-01, DOC-01 +## Milestone v0.2 -**Success criteria:** -- Local workflow request succeeds and returns canonical events. -- Tests, lint, type checks, and Docker build pass. -- Foundry mode uses Next Gen agent references and managed identity. -- Public documentation states deployment and security boundaries. - -Status: Complete - -## Phase 2: Telemetry Hardening - -**Goal:** Wire OpenTelemetry end-to-end with lifecycle span events, W3C trace propagation, and Application Insights exporter. - -**Requirements:** TEL-01, TEL-02, TEL-03, TEL-04 - -**Success criteria:** -- Every /api/v1/workflows request creates a `cas.api.workflows.execute` span with correlation_id, run_id, and intent attributes. -- Span events `workflow.started`, `workflow.completed`, and `workflow.failed` are emitted at the appropriate lifecycle points. -- W3C traceparent/tracestate headers on inbound requests are extracted and linked as parent context. -- Application Insights exporter activates when APPLICATIONINSIGHTS_CONNECTION_STRING is set; no-op otherwise. -- All telemetry behaviours verified by pytest with InMemorySpanExporter. - -Status: Complete - -## Phase 3: Docker + CI Publish - -**Goal:** Containerize the app with a production-grade multi-stage Dockerfile and publish the image to GHCR on merge to main. - -**Requirements:** DOCK-01, DOCK-02, DOCK-03 - -**Success criteria:** -- Multi-stage Dockerfile builds a linux/amd64 image, runs as non-root `appuser`, exposes port 8080, and health-checks via /health/ready. -- docker-compose.yml starts the local dev stack with env stubs using .env.example. -- CI docker job builds, smoke-tests (/health/live + /health/ready), and on push to main pushes to ghcr.io/coding-autopilot-system/cas-reference-product. - -Status: Complete +*To be defined via /gsd-new-milestone* diff --git a/.planning/REQUIREMENTS.md b/.planning/milestones/v0.1-REQUIREMENTS.md similarity index 100% rename from .planning/REQUIREMENTS.md rename to .planning/milestones/v0.1-REQUIREMENTS.md diff --git a/.planning/milestones/v0.1-ROADMAP.md b/.planning/milestones/v0.1-ROADMAP.md new file mode 100644 index 0000000..d033ad4 --- /dev/null +++ b/.planning/milestones/v0.1-ROADMAP.md @@ -0,0 +1,43 @@ +# Roadmap: CAS Reference Product + +## Phase 1: Public v0.1 Reference Application + +**Goal:** Deliver a locally runnable, cloud-ready reference workload without deploying Azure resources. + +**Requirements:** API-01, AGENT-01, ID-01, CONTRACT-01, OBS-01, OPS-01, PLAT-01, QUAL-01, DOC-01 + +**Success criteria:** +- Local workflow request succeeds and returns canonical events. +- Tests, lint, type checks, and Docker build pass. +- Foundry mode uses Next Gen agent references and managed identity. +- Public documentation states deployment and security boundaries. + +Status: Complete + +## Phase 2: Telemetry Hardening + +**Goal:** Wire OpenTelemetry end-to-end with lifecycle span events, W3C trace propagation, and Application Insights exporter. + +**Requirements:** TEL-01, TEL-02, TEL-03, TEL-04 + +**Success criteria:** +- Every /api/v1/workflows request creates a `cas.api.workflows.execute` span with correlation_id, run_id, and intent attributes. +- Span events `workflow.started`, `workflow.completed`, and `workflow.failed` are emitted at the appropriate lifecycle points. +- W3C traceparent/tracestate headers on inbound requests are extracted and linked as parent context. +- Application Insights exporter activates when APPLICATIONINSIGHTS_CONNECTION_STRING is set; no-op otherwise. +- All telemetry behaviours verified by pytest with InMemorySpanExporter. + +Status: Complete + +## Phase 3: Docker + CI Publish + +**Goal:** Containerize the app with a production-grade multi-stage Dockerfile and publish the image to GHCR on merge to main. + +**Requirements:** DOCK-01, DOCK-02, DOCK-03 + +**Success criteria:** +- Multi-stage Dockerfile builds a linux/amd64 image, runs as non-root `appuser`, exposes port 8080, and health-checks via /health/ready. +- docker-compose.yml starts the local dev stack with env stubs using .env.example. +- CI docker job builds, smoke-tests (/health/live + /health/ready), and on push to main pushes to ghcr.io/coding-autopilot-system/cas-reference-product. + +Status: Complete diff --git a/infra/modules/function-ingress.bicep b/infra/modules/function-ingress.bicep index 1f80d2b..ddfb9dc 100644 --- a/infra/modules/function-ingress.bicep +++ b/infra/modules/function-ingress.bicep @@ -26,7 +26,6 @@ resource functionApp 'Microsoft.Web/sites@2024-04-01' = { httpsOnly: true publicNetworkAccess: 'Enabled' siteConfig: { - linuxFxVersion: 'Python|3.12' minTlsVersion: '1.2' ftpsState: 'Disabled' appSettings: [ @@ -36,6 +35,25 @@ resource functionApp 'Microsoft.Web/sites@2024-04-01' = { { name: 'APPLICATIONINSIGHTS_CONNECTION_STRING', value: applicationInsightsConnectionString } ] } + functionAppConfig: { + deployment: { + storage: { + type: 'blobContainer' + value: 'https://${storageAccountName}.blob.${environment().suffixes.storage}/app-package' + authentication: { + type: 'SystemAssignedIdentity' + } + } + } + scaleAndConcurrency: { + maximumInstanceCount: 100 + instanceMemoryMB: 2048 + } + runtime: { + name: 'python' + version: '3.12' + } + } } } @@ -53,5 +71,15 @@ resource queueContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = } } +resource blobContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(storageAccountId, functionApp.id, 'blob-contributor') + scope: storageAccount + properties: { + principalId: functionApp.identity.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe') + } +} + output id string = functionApp.id output principalId string = functionApp.identity.principalId diff --git a/infra/modules/storage.bicep b/infra/modules/storage.bicep index 824bfc1..6b5a99e 100644 --- a/infra/modules/storage.bicep +++ b/infra/modules/storage.bicep @@ -27,6 +27,16 @@ resource workQueue 'Microsoft.Storage/storageAccounts/queueServices/queues@2023- name: 'cas-work-items' } +resource blobService 'Microsoft.Storage/storageAccounts/blobServices@2023-05-01' = { + parent: account + name: 'default' +} + +resource deploymentContainer 'Microsoft.Storage/storageAccounts/blobServices/containers@2023-05-01' = { + parent: blobService + name: 'app-package' +} + output id string = account.id output name string = account.name output queueName string = workQueue.name