Publish CSOC-WP-0005 resource demand and cost evidence
Add low/base/high demand forecasts, service objectives with timestamped observations, and workload operations labor for resource:tenant:coulomb:coulomb-social.
This commit is contained in:
parent
b8154b8e7d
commit
c521adc2f9
10 changed files with 667 additions and 14 deletions
|
|
@ -78,7 +78,8 @@ The rebuild is deliberately **product-faithful first**: UI and content parity ma
|
|||
- `docs/adr/ADR-0002-space-content-forgejo-markdown.md` — space content as markdown in Forgejo
|
||||
- `docs/deploy.md` — deploy + spaces operator runbook
|
||||
- `workplans/CSOC-WP-0001-bubble-io-exit-assessment.md` — Bubble inventory/migration **after** product foundation
|
||||
- `workplans/CSOC-WP-0005-resource-demand-and-cost-evidence.md` — resource evidence for platform cost control
|
||||
- `workplans/CSOC-WP-0005-resource-demand-and-cost-evidence.md` — **finished**: demand/SLO/labor evidence for resource-control
|
||||
- `docs/resource-evidence/` — workload demand forecasts, observations, labor
|
||||
- `the-custodian/docs/coulomb-social-rebuild-seed.md` — original workplan seed (CUST-WP-0058-T08)
|
||||
- `the-custodian/canon/standards/business-app-service-contract_v0.1.md`
|
||||
- NetKingdom: IAM Profile, user-engine boundary, KeyCape/Keycloak modes
|
||||
|
|
|
|||
3
SCOPE.md
3
SCOPE.md
|
|
@ -72,7 +72,8 @@ coulomb.social connects people around shared projects and complementary capabili
|
|||
- Finished identity path: **`CSOC-WP-0002`**, **`CSOC-WP-0003`** (Case A; Case B residual intakes)
|
||||
- Content ADR: `docs/adr/ADR-0002-space-content-forgejo-markdown.md`
|
||||
- Operator: `docs/deploy.md` runbook; residuals `docs/intakes/csoc-residuals.md`
|
||||
- Open: bulk Bubble migration (`CSOC-WP-0001`); resource evidence (`CSOC-WP-0005`); public registration residuals (`CSOC-IN-0001`/`0002`, NK-WP-0025)
|
||||
- Finished resource evidence: **`CSOC-WP-0005`** → `docs/resource-evidence/`
|
||||
- Open: bulk Bubble migration (`CSOC-WP-0001`); public registration residuals (`CSOC-IN-0001`/`0002`, NK-WP-0025)
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
| workplan | CSOC-WP-0002 | done | — | workplans/CSOC-WP-0002-netkingdom-user-management-reestablish.md |
|
||||
| workplan | CSOC-WP-0003 | finished | — | workplans/CSOC-WP-0003-self-registration-and-assurance.md |
|
||||
| workplan | CSOC-WP-0004 | finished | — | workplans/CSOC-WP-0004-app-shell-and-space-content.md |
|
||||
| workplan | CSOC-WP-0005 | ready | — | workplans/CSOC-WP-0005-resource-demand-and-cost-evidence.md |
|
||||
| workplan | CSOC-WP-0005 | finished | — | workplans/CSOC-WP-0005-resource-demand-and-cost-evidence.md |
|
||||
| task | CSOC-WP-0001-T01 | todo | — | workplans/CSOC-WP-0001-bubble-io-exit-assessment.md |
|
||||
| task | CSOC-WP-0001-T02 | todo | — | workplans/CSOC-WP-0001-bubble-io-exit-assessment.md |
|
||||
| task | CSOC-WP-0001-T03 | wait | — | workplans/CSOC-WP-0001-bubble-io-exit-assessment.md |
|
||||
|
|
@ -36,8 +36,8 @@
|
|||
| task | CSOC-WP-0004-T05 | done | — | workplans/CSOC-WP-0004-app-shell-and-space-content.md |
|
||||
| task | CSOC-WP-0004-T06 | done | — | workplans/CSOC-WP-0004-app-shell-and-space-content.md |
|
||||
| task | CSOC-WP-0004-T07 | done | — | workplans/CSOC-WP-0004-app-shell-and-space-content.md |
|
||||
| task | CSOC-WP-0005-T01 | todo | — | workplans/CSOC-WP-0005-resource-demand-and-cost-evidence.md |
|
||||
| task | CSOC-WP-0005-T02 | todo | — | workplans/CSOC-WP-0005-resource-demand-and-cost-evidence.md |
|
||||
| task | CSOC-WP-0005-T03 | todo | — | workplans/CSOC-WP-0005-resource-demand-and-cost-evidence.md |
|
||||
| task | CSOC-WP-0005-T01 | done | — | workplans/CSOC-WP-0005-resource-demand-and-cost-evidence.md |
|
||||
| task | CSOC-WP-0005-T02 | done | — | workplans/CSOC-WP-0005-resource-demand-and-cost-evidence.md |
|
||||
| task | CSOC-WP-0005-T03 | done | — | workplans/CSOC-WP-0005-resource-demand-and-cost-evidence.md |
|
||||
| intake | CSOC-IN-0001 | open | blue | docs/intakes/csoc-residuals.md |
|
||||
| intake | CSOC-IN-0002 | open | green | docs/intakes/csoc-residuals.md |
|
||||
|
|
|
|||
30
docs/resource-evidence/README.md
Normal file
30
docs/resource-evidence/README.md
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# Resource demand and cost evidence
|
||||
|
||||
Workload-owned evidence for
|
||||
`resource:tenant:coulomb:coulomb-social` (CSOC-WP-0005).
|
||||
|
||||
**Authority boundary**
|
||||
|
||||
| Concern | Owner |
|
||||
|---------|--------|
|
||||
| Demand forecasts, app observations, service objectives, app labor | **this repo** |
|
||||
| Cluster / host capacity and utilization | `railiance-cluster` / `railiance-infra` |
|
||||
| Shared Postgres (`apps-pg`) | `railiance-platform` |
|
||||
| Forgejo storage (space markdown SoR) | `railiance-forge` |
|
||||
| Booked financial facts / invoices | `fin-hub` |
|
||||
| Portfolio forecast join / optimization | `resource-control` |
|
||||
|
||||
Do **not** put secret values, provider credentials, or invoices here.
|
||||
|
||||
## Documents
|
||||
|
||||
| File | Task | Content |
|
||||
|------|------|---------|
|
||||
| `demand-forecast-2026-08.md` | T01 | Narrative + assumptions |
|
||||
| `demand-forecast-2026-08.json` | T01 | Machine-readable low/base/high proxies |
|
||||
| `service-objectives-and-observations-2026-08.md` | T02 | SLOs + timestamped observations |
|
||||
| `service-objectives-and-observations-2026-08.json` | T02 | Stable units for join |
|
||||
| `workload-operations-labor-2026-08.md` | T03 | Setup + recurring app labor |
|
||||
|
||||
Inventory pointer (resource-control):
|
||||
`resource-control/data/resources/coulomb-social-production.json`.
|
||||
145
docs/resource-evidence/demand-forecast-2026-08.json
Normal file
145
docs/resource-evidence/demand-forecast-2026-08.json
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
{
|
||||
"schema_version": "0.1",
|
||||
"record_kind": "workload_demand_forecast",
|
||||
"resource_id": "resource:tenant:coulomb:coulomb-social",
|
||||
"service_id": "coulomb-social",
|
||||
"workload_id": "coulomb-social",
|
||||
"tenant_id": "tenant:coulomb",
|
||||
"environment": "production",
|
||||
"cost_attribution_key": "resource:tenant:coulomb:coulomb-social",
|
||||
"currency": "EUR",
|
||||
"forecast_version": "csoc-demand-2026-08-v1",
|
||||
"created_at": "2026-08-12T09:03:47Z",
|
||||
"horizon_months": 12,
|
||||
"planning_period": {
|
||||
"start": "2026-09-01",
|
||||
"end": "2027-08-31"
|
||||
},
|
||||
"tenancy_model": {
|
||||
"deployment_shape": "instance_per_client",
|
||||
"this_record_scope": "single Coulomb reference instance on shared Railiance capacity",
|
||||
"current_tenant": "tenant:coulomb",
|
||||
"external_client_instances": "each future paying client is a separate deployment and its own resource id — not rolled into these scenarios"
|
||||
},
|
||||
"declared_capacity_floor": {
|
||||
"replicas": 1,
|
||||
"cpu_request_millicores": 100,
|
||||
"cpu_limit_millicores": 1000,
|
||||
"memory_request_mi": 256,
|
||||
"memory_limit_mi": 1024,
|
||||
"source": "railiance-apps/charts/coulomb-social/values.yaml"
|
||||
},
|
||||
"proxies": {
|
||||
"units": {
|
||||
"active_tenants": "count of tenant_id values with activity in period",
|
||||
"active_members": "count of Member rows with session activity in period (proxy: monthly active)",
|
||||
"http_requests_per_month": "application HTTP requests (ingress to app Service)",
|
||||
"oidc_logins_per_month": "successful OIDC/dev login completions",
|
||||
"background_jobs_per_month": "async/worker jobs (none in v1 runtime — reserved)",
|
||||
"app_database_gb": "logical size of coulomb_social_db on apps-pg",
|
||||
"app_database_growth_pct_per_month": "month-over-month logical DB growth",
|
||||
"stored_media_gb": "app-owned binary media (PV or object store); Forgejo markdown is NOT counted here",
|
||||
"forgejo_content_gb_bound": "markdown/assets bound for spaces of this tenant (shared Forgejo service; attribution only)",
|
||||
"ingress_gb_per_month": "bytes into the app Service",
|
||||
"egress_gb_per_month": "bytes out of the app pod (HTML + API responses; excludes Forgejo browser edits)",
|
||||
"cpu_request_millicores": "declared Kubernetes request",
|
||||
"memory_request_mi": "declared Kubernetes request",
|
||||
"operator_hours_per_month": "workload-owned ops labor hours (see labor doc)"
|
||||
}
|
||||
},
|
||||
"scenarios": {
|
||||
"low": {
|
||||
"label": "parallel-host operator use (current posture)",
|
||||
"description": "app.coulomb.social live; apex remains Bubble; handful of operator accounts; no bulk member migration.",
|
||||
"active_tenants": 1,
|
||||
"active_members": 5,
|
||||
"http_requests_per_month": 5000,
|
||||
"oidc_logins_per_month": 80,
|
||||
"background_jobs_per_month": 0,
|
||||
"app_database_gb": 0.1,
|
||||
"app_database_growth_pct_per_month": 5,
|
||||
"stored_media_gb": 0,
|
||||
"forgejo_content_gb_bound": 0.01,
|
||||
"ingress_gb_per_month": 0.5,
|
||||
"egress_gb_per_month": 1,
|
||||
"cpu_request_millicores": 100,
|
||||
"cpu_limit_millicores": 1000,
|
||||
"memory_request_mi": 256,
|
||||
"memory_limit_mi": 1024,
|
||||
"replicas": 1,
|
||||
"operator_hours_per_month": 2,
|
||||
"operator_hourly_eur": 60
|
||||
},
|
||||
"base": {
|
||||
"label": "Coulomb community active on rebuild",
|
||||
"description": "Members and spaces actively used on app host; Bubble still may exist but primary day-to-day for Coulomb operators/members shifts to rebuild; still single tenant:coulomb instance.",
|
||||
"active_tenants": 1,
|
||||
"active_members": 50,
|
||||
"http_requests_per_month": 150000,
|
||||
"oidc_logins_per_month": 1500,
|
||||
"background_jobs_per_month": 0,
|
||||
"app_database_gb": 1,
|
||||
"app_database_growth_pct_per_month": 10,
|
||||
"stored_media_gb": 2,
|
||||
"forgejo_content_gb_bound": 0.5,
|
||||
"ingress_gb_per_month": 5,
|
||||
"egress_gb_per_month": 15,
|
||||
"cpu_request_millicores": 200,
|
||||
"cpu_limit_millicores": 1000,
|
||||
"memory_request_mi": 512,
|
||||
"memory_limit_mi": 1024,
|
||||
"replicas": 1,
|
||||
"operator_hours_per_month": 4,
|
||||
"operator_hourly_eur": 60
|
||||
},
|
||||
"high": {
|
||||
"label": "full Bubble parity load on this Coulomb instance",
|
||||
"description": "All Coulomb spaces/content migrated; peak community concurrency; optional second replica for HA; still NOT multi-client — external clients would be separate instances.",
|
||||
"active_tenants": 1,
|
||||
"active_members": 500,
|
||||
"http_requests_per_month": 2000000,
|
||||
"oidc_logins_per_month": 20000,
|
||||
"background_jobs_per_month": 5000,
|
||||
"app_database_gb": 10,
|
||||
"app_database_growth_pct_per_month": 15,
|
||||
"stored_media_gb": 50,
|
||||
"forgejo_content_gb_bound": 20,
|
||||
"ingress_gb_per_month": 40,
|
||||
"egress_gb_per_month": 120,
|
||||
"cpu_request_millicores": 500,
|
||||
"cpu_limit_millicores": 2000,
|
||||
"memory_request_mi": 1024,
|
||||
"memory_limit_mi": 2048,
|
||||
"replicas": 2,
|
||||
"operator_hours_per_month": 8,
|
||||
"operator_hourly_eur": 60
|
||||
}
|
||||
},
|
||||
"monthly_labor_eur_proxy": {
|
||||
"low": 120.0,
|
||||
"base": 240.0,
|
||||
"high": 480.0,
|
||||
"formula": "operator_hours_per_month × operator_hourly_eur",
|
||||
"note": "Infrastructure EUR is unknown here (allocated share of cluster/apps-pg/ingress/identity). Leave infrastructure null in cost joins until platform/fin-hub supplies figures."
|
||||
},
|
||||
"assumptions": [
|
||||
"Scenarios are per-instance demand for tenant:coulomb, not fleet-wide multi-tenant aggregation.",
|
||||
"Current production posture (2026-08) matches low: parallel host, identity + shell + spaces MVP, Bubble still on apex.",
|
||||
"Space page bodies live in Forgejo (ADR-0002); forgejo_content_gb_bound is attribution input for shared Forgejo, not a claim that coulomb-social operates that storage.",
|
||||
"App media PV is currently disabled in chart; stored_media_gb remains 0 until object storage or PV is enabled.",
|
||||
"No application worker/queue in v1; background_jobs_per_month is 0 until a job system exists (high reserves headroom).",
|
||||
"OIDC/identity platform traffic cost is not counted as app infrastructure; only app HTTP path is in http_requests_per_month.",
|
||||
"Database is coulomb_social_db on shared apps-pg; logical size ownership is workload, physical volume ownership is railiance-platform.",
|
||||
"CPU/memory figures are declared requirements for rightsizing; observed utilization is cluster authority when sampled.",
|
||||
"Operator hourly rate €60 matches resource-control backup labor convention for comparability; not a payroll fact.",
|
||||
"Falsifiable: after each calendar month, compare active_members, http_requests, app_database_gb, and operator_hours against the chosen scenario band."
|
||||
],
|
||||
"source_evidence": [
|
||||
"docs/resource-evidence/demand-forecast-2026-08.md",
|
||||
"docs/adr/ADR-0002-space-content-forgejo-markdown.md",
|
||||
"docs/deploy.md",
|
||||
"railiance-apps/charts/coulomb-social/values.yaml",
|
||||
"resource-control/data/resources/coulomb-social-production.json",
|
||||
"workplans/CSOC-WP-0005-resource-demand-and-cost-evidence.md"
|
||||
]
|
||||
}
|
||||
95
docs/resource-evidence/demand-forecast-2026-08.md
Normal file
95
docs/resource-evidence/demand-forecast-2026-08.md
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
# Workload demand forecast — coulomb-social (2026-08)
|
||||
|
||||
| Field | Value |
|
||||
|-------|--------|
|
||||
| Resource | `resource:tenant:coulomb:coulomb-social` |
|
||||
| Workplan | CSOC-WP-0005-T01 |
|
||||
| Forecast version | `csoc-demand-2026-08-v1` |
|
||||
| Created | 2026-08-12T09:03:47Z |
|
||||
| Machine record | `demand-forecast-2026-08.json` |
|
||||
|
||||
## Scope
|
||||
|
||||
Demand for **this production instance** (Coulomb reference tenant on
|
||||
Railiance). Deployment shape is **instance-per-client** (DR-1 C): future
|
||||
external customers are **separate instances** and separate resource ids —
|
||||
they are **not** folded into the high scenario.
|
||||
|
||||
| Case | What it models |
|
||||
|------|----------------|
|
||||
| **low** | Current parallel-host posture: few operators, Bubble still full product on apex |
|
||||
| **base** | Coulomb community day-to-day on the rebuild (still one tenant) |
|
||||
| **high** | Full Bubble-parity load on this Coulomb instance (HA-ish replicas/resources) |
|
||||
|
||||
## Proxies (stable units)
|
||||
|
||||
| Proxy | Unit | Notes |
|
||||
|-------|------|--------|
|
||||
| active_tenants | count | Expected 1 for this instance |
|
||||
| active_members | MAU-ish Member count | App-owned |
|
||||
| http_requests_per_month | count | App Service ingress |
|
||||
| oidc_logins_per_month | count | Successful app logins |
|
||||
| background_jobs_per_month | count | 0 until workers exist |
|
||||
| app_database_gb | GB logical | `coulomb_social_db` on apps-pg |
|
||||
| stored_media_gb | GB | App-owned binaries only |
|
||||
| forgejo_content_gb_bound | GB | Attribution for space markdown on shared Forgejo |
|
||||
| ingress_gb / egress_gb | GB/month | App path only |
|
||||
| cpu/memory request·limit | mCPU / Mi | Declared K8s requirements |
|
||||
| operator_hours_per_month | hours | Workload labor (T03) |
|
||||
|
||||
## Scenario table (monthly)
|
||||
|
||||
| Proxy | low | base | high |
|
||||
|-------|----:|-----:|-----:|
|
||||
| active_tenants | 1 | 1 | 1 |
|
||||
| active_members | 5 | 50 | 500 |
|
||||
| http_requests | 5 000 | 150 000 | 2 000 000 |
|
||||
| oidc_logins | 80 | 1 500 | 20 000 |
|
||||
| background_jobs | 0 | 0 | 5 000 |
|
||||
| app_database_gb | 0.1 | 1 | 10 |
|
||||
| DB growth %/mo | 5 | 10 | 15 |
|
||||
| stored_media_gb | 0 | 2 | 50 |
|
||||
| forgejo_content_gb_bound | 0.01 | 0.5 | 20 |
|
||||
| ingress_gb | 0.5 | 5 | 40 |
|
||||
| egress_gb | 1 | 15 | 120 |
|
||||
| cpu request (m) | 100 | 200 | 500 |
|
||||
| mem request (Mi) | 256 | 512 | 1024 |
|
||||
| replicas | 1 | 1 | 2 |
|
||||
| operator h/mo | 2 | 4 | 8 |
|
||||
| labor €/mo @ €60/h | 120 | 240 | 480 |
|
||||
|
||||
Infrastructure EUR is **not invented** here. Cost joins should treat
|
||||
infrastructure as an allocated share of cluster, apps-pg, ingress, and
|
||||
identity platform once those owners and fin-hub supply figures.
|
||||
|
||||
## Capacity floor (current deploy declaration)
|
||||
|
||||
From `railiance-apps` chart defaults (production values do not override
|
||||
resources as of 2026-08):
|
||||
|
||||
| Dimension | Value |
|
||||
|-----------|--------|
|
||||
| replicas | 1 |
|
||||
| cpu request / limit | 100m / 1000m |
|
||||
| memory request / limit | 256Mi / 1Gi |
|
||||
| media PV | disabled |
|
||||
| Image tag (values) | `7fcd0cf` (railiance-apps helm values; may lag git HEAD) |
|
||||
|
||||
## How resource-control should use this
|
||||
|
||||
1. Pick scenario band from observed MAU / requests (or default **low** until
|
||||
Bubble migration starts).
|
||||
2. Feed proxies into monthly forecast/actual control (null infrastructure
|
||||
until platform prices exist).
|
||||
3. Attribute Forgejo-bound content via `forgejo_content_gb_bound` without
|
||||
double-counting storage in the app resource.
|
||||
4. Recalibrate after three comparable months (MAPE on members, requests, DB
|
||||
GB, labor hours).
|
||||
|
||||
## Assumptions and falsifiability
|
||||
|
||||
See JSON `assumptions` array. Primary falsifiers after each calendar month:
|
||||
|
||||
- measured `active_members` outside the active scenario band by >2×
|
||||
- `app_database_gb` growth vs declared growth %
|
||||
- operator hours vs T03 labor log
|
||||
|
|
@ -0,0 +1,210 @@
|
|||
{
|
||||
"schema_version": "0.1",
|
||||
"record_kind": "service_objectives_and_usage_observations",
|
||||
"resource_id": "resource:tenant:coulomb:coulomb-social",
|
||||
"service_id": "coulomb-social",
|
||||
"workload_id": "coulomb-social",
|
||||
"tenant_id": "tenant:coulomb",
|
||||
"environment": "production",
|
||||
"cost_attribution_key": "resource:tenant:coulomb:coulomb-social",
|
||||
"created_at": "2026-08-12T09:03:47Z",
|
||||
"service_objectives": {
|
||||
"availability": {
|
||||
"target": "99.5_percent_monthly",
|
||||
"scope": "HTTPS app.coulomb.social application responses excluding scheduled maintenance and dependency outages (OIDC, apps-pg, cluster)",
|
||||
"measurement": "synthetic GET /healthz success ratio + ingress 5xx from platform telemetry when available",
|
||||
"notes": "Not a contractual SLA; planning objective for infrastructure options."
|
||||
},
|
||||
"latency": {
|
||||
"healthz_p99_ms": 500,
|
||||
"authenticated_html_p95_ms": 1500,
|
||||
"space_markdown_render_p95_ms": 3000,
|
||||
"notes": "Markdown path includes Forgejo fetch; cold cache may exceed target — track separately."
|
||||
},
|
||||
"recovery": {
|
||||
"rpo_minutes": 60,
|
||||
"rto_minutes": 240,
|
||||
"notes": "RPO/RTO for app DB via apps-pg backup ownership; content RPO/RTO inherits Forgejo backup policy for bound repos."
|
||||
},
|
||||
"retention": {
|
||||
"app_database_backup_days": 30,
|
||||
"application_logs_days": 14,
|
||||
"session_cookie": "browser session; no long-lived app refresh tokens in v1",
|
||||
"notes": "Backup retention executed by apps-pg/platform; app requires ≥30 days logical recoverability."
|
||||
},
|
||||
"tenant_isolation": {
|
||||
"model": "tenant_id column isolation within instance + instance_per_client deployments",
|
||||
"default_tenant": "tenant:coulomb",
|
||||
"cross_tenant_list": "forbidden — Space queries filter by session tenant_id",
|
||||
"identity": "NetKingdom OIDC (issuer, subject) Member binding; no local passwords"
|
||||
},
|
||||
"security": {
|
||||
"authn": "OIDC public client + session cookies Secure/HttpOnly/SameSite=Lax in prod",
|
||||
"secrets": "K8s Secret coulomb-social-env / OpenBao; never in git",
|
||||
"content_xss": "bleach-sanitized markdown HTML"
|
||||
}
|
||||
},
|
||||
"observations": [
|
||||
{
|
||||
"name": "public_healthz",
|
||||
"value": "ok",
|
||||
"unit": "status",
|
||||
"observed_at": "2026-08-12T09:03:47Z",
|
||||
"method": "curl -fsS https://app.coulomb.social/healthz",
|
||||
"authority": "coulomb-social"
|
||||
},
|
||||
{
|
||||
"name": "public_landing_http_status",
|
||||
"value": "200",
|
||||
"unit": "http_status",
|
||||
"observed_at": "2026-08-12T09:03:47Z",
|
||||
"method": "curl -o /dev/null -w status https://app.coulomb.social/",
|
||||
"authority": "coulomb-social"
|
||||
},
|
||||
{
|
||||
"name": "demo_fixture_raw_bytes",
|
||||
"value": "586",
|
||||
"unit": "bytes",
|
||||
"observed_at": "2026-08-12T09:03:47Z",
|
||||
"method": "GET Forgejo raw docs/space-fixtures/demo/pages/index.md",
|
||||
"authority": "coulomb-social + forgejo.coulomb.social public raw"
|
||||
},
|
||||
{
|
||||
"name": "declared_replicas",
|
||||
"value": "1",
|
||||
"unit": "count",
|
||||
"observed_at": "2026-08-12",
|
||||
"method": "chart values replicaCount",
|
||||
"authority": "railiance-apps/charts/coulomb-social/values.yaml"
|
||||
},
|
||||
{
|
||||
"name": "declared_cpu_request_millicores",
|
||||
"value": "100",
|
||||
"unit": "millicores",
|
||||
"observed_at": "2026-08-12",
|
||||
"method": "chart resources.requests.cpu",
|
||||
"authority": "railiance-apps"
|
||||
},
|
||||
{
|
||||
"name": "declared_memory_request_mi",
|
||||
"value": "256",
|
||||
"unit": "Mi",
|
||||
"observed_at": "2026-08-12",
|
||||
"method": "chart resources.requests.memory",
|
||||
"authority": "railiance-apps"
|
||||
},
|
||||
{
|
||||
"name": "declared_cpu_limit_millicores",
|
||||
"value": "1000",
|
||||
"unit": "millicores",
|
||||
"observed_at": "2026-08-12",
|
||||
"method": "chart resources.limits.cpu",
|
||||
"authority": "railiance-apps"
|
||||
},
|
||||
{
|
||||
"name": "declared_memory_limit_mi",
|
||||
"value": "1024",
|
||||
"unit": "Mi",
|
||||
"observed_at": "2026-08-12",
|
||||
"method": "chart resources.limits.memory",
|
||||
"authority": "railiance-apps"
|
||||
},
|
||||
{
|
||||
"name": "media_persistence_enabled",
|
||||
"value": "false",
|
||||
"unit": "bool",
|
||||
"observed_at": "2026-08-12",
|
||||
"method": "chart persistence.media.enabled",
|
||||
"authority": "railiance-apps"
|
||||
},
|
||||
{
|
||||
"name": "helm_image_tag",
|
||||
"value": "7fcd0cf",
|
||||
"unit": "git_sha_short",
|
||||
"observed_at": "2026-08-12",
|
||||
"method": "helm/coulomb-social-values.yaml image.tag",
|
||||
"authority": "railiance-apps"
|
||||
},
|
||||
{
|
||||
"name": "portfolio_ready_replicas",
|
||||
"value": "1",
|
||||
"unit": "count",
|
||||
"observed_at": "2026-08-11",
|
||||
"method": "Kubernetes API sample in RESOURCE-WP-0003 initial portfolio discovery",
|
||||
"authority": "resource-control discovery (reef-railiance)"
|
||||
},
|
||||
{
|
||||
"name": "commissioned_on",
|
||||
"value": "2026-08-09",
|
||||
"unit": "date",
|
||||
"observed_at": "2026-08-11",
|
||||
"method": "inventory record lifecycle.commissioned_on",
|
||||
"authority": "resource-control/data/resources/coulomb-social-production.json"
|
||||
},
|
||||
{
|
||||
"name": "app_database_gb_logical",
|
||||
"value": "unknown",
|
||||
"unit": "GB",
|
||||
"observed_at": "2026-08-12",
|
||||
"method": "not measured this session (kubectl/apps-pg access unavailable)",
|
||||
"authority": "coulomb-social — gap; platform may supply"
|
||||
},
|
||||
{
|
||||
"name": "production_member_count",
|
||||
"value": "unknown",
|
||||
"unit": "count",
|
||||
"observed_at": "2026-08-12",
|
||||
"method": "not queried (no production DB shell this session)",
|
||||
"authority": "coulomb-social — gap"
|
||||
},
|
||||
{
|
||||
"name": "observed_cpu_millicores",
|
||||
"value": "unknown",
|
||||
"unit": "millicores",
|
||||
"observed_at": "2026-08-12",
|
||||
"method": "metrics-server sample unavailable this session",
|
||||
"authority": "railiance-cluster when sampled"
|
||||
},
|
||||
{
|
||||
"name": "observed_memory_mi",
|
||||
"value": "unknown",
|
||||
"unit": "Mi",
|
||||
"observed_at": "2026-08-12",
|
||||
"method": "metrics-server sample unavailable this session",
|
||||
"authority": "railiance-cluster when sampled"
|
||||
},
|
||||
{
|
||||
"name": "local_dev_member_count",
|
||||
"value": "2",
|
||||
"unit": "count",
|
||||
"observed_at": "2026-08-12T09:03:47Z",
|
||||
"method": "local sqlite Member.objects.count() after pytest/dev use — not production",
|
||||
"authority": "coulomb-social workstation (non-prod)"
|
||||
}
|
||||
],
|
||||
"dependency_slo_inheritance": [
|
||||
{
|
||||
"dependency": "resource:railiance:apps-pg",
|
||||
"inherits": ["database backup", "DB RPO/RTO physical path"]
|
||||
},
|
||||
{
|
||||
"dependency": "resource:railiance:reef-railiance:k3s",
|
||||
"inherits": ["node availability", "pod scheduling"]
|
||||
},
|
||||
{
|
||||
"dependency": "resource:railiance:forgejo",
|
||||
"inherits": ["space markdown durability", "git history"]
|
||||
},
|
||||
{
|
||||
"dependency": "NetKingdom KeyCape / Authelia",
|
||||
"inherits": ["authentication availability", "MFA path"]
|
||||
}
|
||||
],
|
||||
"source_evidence": [
|
||||
"docs/resource-evidence/service-objectives-and-observations-2026-08.md",
|
||||
"docs/deploy.md",
|
||||
"docs/identity/smoke.md",
|
||||
"docs/adr/ADR-0001-netkingdom-identity.md",
|
||||
"docs/adr/ADR-0002-space-content-forgejo-markdown.md"
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
# Service objectives and usage observations — coulomb-social (2026-08)
|
||||
|
||||
| Field | Value |
|
||||
|-------|--------|
|
||||
| Resource | `resource:tenant:coulomb:coulomb-social` |
|
||||
| Workplan | CSOC-WP-0005-T02 |
|
||||
| Created | 2026-08-12T09:03:47Z |
|
||||
| Machine record | `service-objectives-and-observations-2026-08.json` |
|
||||
|
||||
## Service objectives (application-owned)
|
||||
|
||||
These are **planning requirements** for evaluating infrastructure options and
|
||||
forecast error — not external contractual SLAs.
|
||||
|
||||
| Domain | Objective | Notes |
|
||||
|--------|-----------|--------|
|
||||
| Availability | 99.5% monthly for app HTTPS | Excludes scheduled maintenance and pure dependency outages |
|
||||
| Latency | `/healthz` p99 ≤ 500 ms | Synthetic-friendly |
|
||||
| Latency | Auth HTML p95 ≤ 1.5 s | App home, session pages |
|
||||
| Latency | Space markdown p95 ≤ 3 s | Includes Forgejo fetch; cold cache separate |
|
||||
| Recovery | RPO ≤ 60 min, RTO ≤ 4 h | DB via apps-pg; content via Forgejo policy |
|
||||
| Retention | DB backups ≥ 30 days | Executed by platform; app requires recoverability |
|
||||
| Retention | App logs ≥ 14 days | Platform log sink when wired |
|
||||
| Isolation | `tenant_id` filter + instance-per-client | No cross-tenant list/detail |
|
||||
| Auth | NetKingdom OIDC; no local passwords | ADR-0001 |
|
||||
| Content safety | Sanitized markdown HTML | ADR-0002 |
|
||||
|
||||
### Dependency inheritance (not double-owned)
|
||||
|
||||
| Dependency | What we inherit |
|
||||
|------------|-----------------|
|
||||
| apps-pg | Physical DB backup/restore mechanics |
|
||||
| reef-railiance k3s | Node/pod availability |
|
||||
| Forgejo | Markdown durability and git history |
|
||||
| KeyCape / Authelia | Sign-in path availability |
|
||||
|
||||
## Observations (timestamped, non-secret)
|
||||
|
||||
| Measure | Value | When | Authority |
|
||||
|---------|-------|------|-----------|
|
||||
| public_healthz | ok | 2026-08-12T09:03:47Z | curl app.coulomb.social |
|
||||
| public_landing_http_status | 200 | 2026-08-12T09:03:47Z | curl |
|
||||
| demo_fixture_raw_bytes | 586 | 2026-08-12T09:03:47Z | Forgejo public raw |
|
||||
| declared_replicas | 1 | 2026-08-12 | railiance-apps chart |
|
||||
| declared_cpu_request_millicores | 100 | 2026-08-12 | chart |
|
||||
| declared_memory_request_mi | 256 | 2026-08-12 | chart |
|
||||
| declared_cpu_limit_millicores | 1000 | 2026-08-12 | chart |
|
||||
| declared_memory_limit_mi | 1024 | 2026-08-12 | chart |
|
||||
| media_persistence_enabled | false | 2026-08-12 | chart |
|
||||
| helm_image_tag | 7fcd0cf | 2026-08-12 | helm values |
|
||||
| portfolio_ready_replicas | 1 | 2026-08-11 | RESOURCE-WP-0003 discovery |
|
||||
| commissioned_on | 2026-08-09 | inventory | resource-control |
|
||||
| app_database_gb_logical | **unknown** | 2026-08-12 | needs apps-pg measure |
|
||||
| production_member_count | **unknown** | 2026-08-12 | needs prod DB shell |
|
||||
| observed_cpu/memory | **unknown** | 2026-08-12 | cluster metrics authority |
|
||||
|
||||
Explicit **unknown** is preferred over invented utilization. Cluster samples
|
||||
belong in railiance-cluster evidence; logical DB size may be published here
|
||||
once an operator can run a non-secret `pg_database_size` (or app management
|
||||
command) without credentials in git.
|
||||
|
||||
## Forecast error measurement
|
||||
|
||||
After each month, compare demand proxies (T01) to:
|
||||
|
||||
1. request/login counts from ingress or app metrics (when exported),
|
||||
2. logical DB size,
|
||||
3. member/space counts from app DB,
|
||||
4. operator hours from T03.
|
||||
|
||||
Record actuals as a dated observation append (new file or JSON revision), never
|
||||
rewrite prior observations.
|
||||
81
docs/resource-evidence/workload-operations-labor-2026-08.md
Normal file
81
docs/resource-evidence/workload-operations-labor-2026-08.md
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
# Workload operations labor — coulomb-social (2026-08)
|
||||
|
||||
| Field | Value |
|
||||
|-------|--------|
|
||||
| Resource | `resource:tenant:coulomb:coulomb-social` |
|
||||
| Workplan | CSOC-WP-0005-T03 |
|
||||
| Created | 2026-08-12T09:03:47Z |
|
||||
| Labor rate (planning) | €60 / hour (resource-control convention; not payroll) |
|
||||
|
||||
## Boundary — count only app workload labor here
|
||||
|
||||
| In scope (coulomb-social) | Out of scope (do not double-count) |
|
||||
|---------------------------|-------------------------------------|
|
||||
| App image build/publish for this service | k3s/node host ops (`railiance-infra` / cluster) |
|
||||
| Helm values / release for coulomb-social | Shared apps-pg admin & backups (`railiance-platform`) |
|
||||
| Django migrations for this app | Ingress controller / cert-manager fleet work |
|
||||
| Seed/bind spaces, Forgejo webhook config for app | Forgejo platform upgrades (`railiance-forge`) |
|
||||
| App incident triage (500s, bad deploy, data bugs) | KeyCape / Authelia / LLDAP platform incidents |
|
||||
| App restore drill participation (app checklist) | Cluster restore of node/volumes |
|
||||
| Content/model product ops (spaces ADR, smoke) | Bubble.io hosting (external product until cutover) |
|
||||
|
||||
## Setup labor (one-time / infrequent)
|
||||
|
||||
Estimates for standing up or re-standing the **Coulomb** production instance.
|
||||
Recorded for total-cost models; not a timesheet.
|
||||
|
||||
| Activity | Hours | Cadence | Notes |
|
||||
|----------|------:|---------|--------|
|
||||
| Scaffold app + identity shell (historical CSOC-WP-0002) | 40 | one-time done | sunk; for amortization models only |
|
||||
| App shell + spaces + Forgejo path (CSOC-WP-0004) | 24 | one-time done | sunk |
|
||||
| KeyCape client registration / redirect updates | 1 | per host change | script: `scripts/register-keycape-client.sh` |
|
||||
| Env secret create/rotate (names via railiance-apps tooling) | 0.5 | per rotate | operator; no secret values in repo |
|
||||
| First deploy + ingress + DNS for app.coulomb.social | 2 | one-time done | with railiance-apps |
|
||||
| Demo space seed + smoke | 0.5 | per env | `seed_demo_space` + browser checklist |
|
||||
| Public registration enablement when NK ready | 2 | once | residual CSOC-IN-0001 |
|
||||
| Bubble migration rehearsal (future CSOC-WP-0001) | 16 | per rehearsal | not yet executed |
|
||||
|
||||
**Setup already sunk (approx):** ~66.5 h for current parallel-host MVP
|
||||
**Near-term setup residual:** ~2.5 h (seed/smoke + registration enable)
|
||||
**Migration rehearsal (planned):** ~16 h when inventory/mapping ready
|
||||
|
||||
## Recurring labor (monthly, steady state)
|
||||
|
||||
Aligned with demand scenarios in `demand-forecast-2026-08.json`.
|
||||
|
||||
| Activity | low h | base h | high h | Notes |
|
||||
|----------|------:|-------:|-------:|--------|
|
||||
| Release: build image, bump tag, deploy, smoke | 1.0 | 1.5 | 2.5 | commit-SHA images |
|
||||
| Migration apply + verify | 0.25 | 0.5 | 1.0 | only when schema changes |
|
||||
| Space content ops (seed/bind/webhook, content incidents) | 0.25 | 0.75 | 2.0 | Forgejo is SoR; app refresh path |
|
||||
| Identity smoke / session diagnostics | 0.25 | 0.5 | 1.0 | Case A; Case B when live |
|
||||
| Incident response (app-owned) | 0.25 | 0.5 | 1.5 | excludes pure platform outages |
|
||||
| Recovery exercise (app checklist against restored DB) | 0 | 0.25 | 0.5 | quarterly average as monthly |
|
||||
| Demand/evidence refresh | 0 | 0 | 0.5 | forecast vs actual notes |
|
||||
| **Total recurring** | **2.0** | **4.0** | **8.0** | matches T01 operator_hours |
|
||||
|
||||
### Monthly labor € proxy (internal only)
|
||||
|
||||
| Scenario | Hours | € @ 60 |
|
||||
|----------|------:|-------:|
|
||||
| low | 2 | 120 |
|
||||
| base | 4 | 240 |
|
||||
| high | 8 | 480 |
|
||||
|
||||
## What not to bill twice
|
||||
|
||||
- **Cluster upgrade weekend** → railiance-cluster / infra labor, even if app is
|
||||
redeployed as a consumer.
|
||||
- **apps-pg vacuum/backup failure** → platform labor; app only spends the hours
|
||||
verifying app health after restore.
|
||||
- **Forgejo disk full** → forge labor; app may open an incident for missing
|
||||
content but content storage is not app labor ownership.
|
||||
- **Authelia MFA outage** → NetKingdom; app documents customer impact only.
|
||||
|
||||
## Evidence links
|
||||
|
||||
- Operator runbook: `docs/deploy.md`
|
||||
- Identity smoke: `docs/identity/smoke.md`
|
||||
- Spaces content: `docs/spaces-content.md`
|
||||
- Residuals: `docs/intakes/csoc-residuals.md`
|
||||
- Demand: `docs/resource-evidence/demand-forecast-2026-08.md`
|
||||
|
|
@ -4,11 +4,11 @@ type: workplan
|
|||
title: "Publish Coulomb Social resource demand and cost evidence"
|
||||
domain: communication
|
||||
repo: coulomb-social
|
||||
status: ready
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: coulomb-social
|
||||
created: "2026-08-11"
|
||||
updated: "2026-08-11"
|
||||
updated: "2026-08-12"
|
||||
related:
|
||||
- CSOC-WP-0004
|
||||
- RESOURCE-WP-0003
|
||||
|
|
@ -24,11 +24,13 @@ Publish workload-owned requirements and observations for
|
|||
or financial authority into this repository. Origin: `RESOURCE-WP-0003-T04`
|
||||
delegated evidence gap.
|
||||
|
||||
**Finished 2026-08-12:** evidence under `docs/resource-evidence/`.
|
||||
|
||||
## T01 — Declare low, base, and high workload demand
|
||||
|
||||
```task
|
||||
id: CSOC-WP-0005-T01
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "d22e42e7-186e-4206-9cf4-c533d6388b13"
|
||||
```
|
||||
|
|
@ -40,11 +42,15 @@ multi-tenant scenarios.
|
|||
|
||||
Done when resource-control can produce falsifiable monthly demand forecasts.
|
||||
|
||||
2026-08-12: `docs/resource-evidence/demand-forecast-2026-08.{md,json}` —
|
||||
low/base/high with units, assumptions, instance-per-client scope (external
|
||||
clients = separate instances), labor € proxy, capacity floor from chart.
|
||||
|
||||
## T02 — Publish service objectives and usage observations
|
||||
|
||||
```task
|
||||
id: CSOC-WP-0005-T02
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "ac078211-3cd9-49d8-baac-c0a1b60278fb"
|
||||
```
|
||||
|
|
@ -57,11 +63,15 @@ owners.
|
|||
Done when infrastructure options can be evaluated against application-owned
|
||||
requirements and forecast error can be measured.
|
||||
|
||||
2026-08-12: `docs/resource-evidence/service-objectives-and-observations-2026-08.{md,json}`
|
||||
— SLOs + timestamped measures; explicit **unknown** for prod DB size, member
|
||||
count, and live CPU/memory (cluster/DB authority).
|
||||
|
||||
## T03 — Record workload operations labor
|
||||
|
||||
```task
|
||||
id: CSOC-WP-0005-T03
|
||||
status: todo
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "a15e630c-6bec-4c50-9622-bce16e1ce418"
|
||||
```
|
||||
|
|
@ -73,8 +83,16 @@ cluster, database, identity, and provider labor.
|
|||
Done when resource-control can include workload labor without double counting
|
||||
platform operations.
|
||||
|
||||
2026-08-12: `docs/resource-evidence/workload-operations-labor-2026-08.md` —
|
||||
setup sunk vs residual, recurring low/base/high hours matching demand, out-of
|
||||
scope table for platform labor.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- [ ] Demand forecasts distinguish current, growth, and external-tenant cases.
|
||||
- [ ] Service objectives and observations have stable units and provenance.
|
||||
- [ ] Workload labor is separated from delegated infrastructure labor.
|
||||
- [x] Demand forecasts distinguish current, growth, and external-tenant cases.
|
||||
- [x] Service objectives and observations have stable units and provenance.
|
||||
- [x] Workload labor is separated from delegated infrastructure labor.
|
||||
|
||||
## Index
|
||||
|
||||
`docs/resource-evidence/README.md`
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue