Confirming and rectifying assumptions
Inspect current assumptions/history for your project and period. Missing evidence, inferred input and measured zero remain different states. Confirmation records review, not missing provider data.
Inspect current assumptions
Operation: assumptions.list · GET /assumptions
Read every registered assumption for a reporting period and optional customer/project. Original defaults, evidence availability, options, confirmed/rectified versions, units, impacts and coverage remain distinct. No evidence is silently confirmed. Exact scope, current creator action/dataset access and tenant ownership apply. Identical successful retries return the original response without extra history or audit. Revisions affect applicable future/current calculations; stored source evidence and historical report snapshots are never rewritten.
Required key scope: assumptions:read. Current creator action: assumptions.read. Eligible plans: free, starter, growth, scale; legacy contracts: free, entry, growth. stable contract. These badges do not override current role, evidence window, quotas or target ownership.
-
Reporting and effective intervals are ordered; tz is a valid IANA time zone.
-
Manual values have no date range; date_range values agree with the ordered range.
-
supersedesId must match the observed current head. Current evidence/options are rechecked under the assumption lock.
-
Rationale is optional in the existing domain contract; provide a meaningful reason for traceability.
Parameters (required flags, defaults, units and bounds are the canonical schema):
View schema or synthetic response
[
{
"in": "query",
"name": "clientId",
"required": false,
"schema": {
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)quot;,
"type": "string"
}
},
{
"example": "11111111-1111-4111-8111-111111111111",
"in": "query",
"name": "projectId",
"required": false,
"schema": {
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)quot;,
"type": "string"
}
},
{
"example": "2026-10-01",
"in": "query",
"name": "start",
"required": true,
"schema": {
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))quot;,
"type": "string"
}
},
{
"example": "2026-10-31",
"in": "query",
"name": "end",
"required": true,
"schema": {
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))quot;,
"type": "string"
}
},
{
"example": "UTC",
"in": "query",
"name": "tz",
"required": true,
"schema": {
"maxLength": 64,
"minLength": 1,
"type": "string"
}
}
]
Success statuses: 200. The JSON response is the saved/read representation. Synthetic examples below show shape, not customer evidence.
Synthetic response:
View schema or synthetic response
{
"canWrite": true,
"coverage": {
"completenessPct": 0,
"freshestAt": null,
"settled": 0,
"stalestAt": null,
"stalestDays": null,
"total": 6
},
"entries": [
{
"actorName": null,
"allowManual": true,
"classification": "financial",
"classificationLabel": "Financial value",
"dataAvailable": true,
"description": "Role-based blended rate used to estimate Oct 1 – Oct 31, 2026 delivery investment. Per-engineer rates would lift precision.",
"effectiveFrom": "2026-10-01",
"effectiveTo": null,
"icon": "coin",
"id": "cost-basis",
"impacts": [
"period_spend",
"invoice_defense"
],
"note": null,
"options": [
{
"label": "Keep per-person rates, role rates otherwise",
"method": "person_then_role",
"range": null,
"value": "$165/h"
}
],
"range": null,
"rationale": null,
"source": "default",
"status": "needs_verification",
"title": "Cost estimate basis",
"unitOrMethod": "person_then_role",
"updatedAt": null,
"value": "$165/h",
"versionId": null
},
{
"actorName": null,
"allowManual": false,
"classification": "quantity",
"classificationLabel": "Quantity",
"dataAvailable": true,
"description": "Items added after the Jan 1, 2026 scope lock count as scope expansion for this report.",
"effectiveFrom": "2026-10-01",
"effectiveTo": null,
"icon": "check",
"id": "scope-baseline",
"impacts": [
"scope_valuation"
],
"note": null,
"options": [
{
"label": "Keep the engagement start as the scope lock",
"method": "engagement_start",
"range": null,
"value": "1 work items"
},
{
"label": "Use the reporting period start",
"method": "period_start",
"range": null,
"value": "3 work items"
}
],
"range": null,
"rationale": null,
"source": "default",
"status": "needs_verification",
"title": "Scope baseline",
"unitOrMethod": "engagement_start",
"updatedAt": null,
"value": "1 work items",
"versionId": null
},
{
"actorName": null,
"allowManual": false,
"classification": "percentage",
"classificationLabel": "Percentage",
"dataAvailable": false,
"description": "Calendar events with explicit project tags only. Untagged meetings are excluded from the coordination estimate.",
"effectiveFrom": "2026-10-01",
"effectiveTo": null,
"icon": "gauge",
"id": "meeting-attribution",
"impacts": [
"coordination_cost"
],
"note": "No calendar events were synced for this period, so coordination cost is counted from nothing.",
"options": [
{
"label": "Keep meetings tagged to this project",
"method": "project_tagged",
"range": null,
"value": "No meetings synced"
}
],
"range": null,
"rationale": null,
"source": "default",
"status": "needs_verification",
"title": "Meeting attribution",
"unitOrMethod": "project_tagged",
"updatedAt": null,
"value": "No meetings synced",
"versionId": null
},
{
"actorName": null,
"allowManual": false,
"classification": "nominal",
"classificationLabel": "Nominal value",
"dataAvailable": false,
"description": "Uses self-reported labels and trailers to identify AI-assisted changes. Explicit AI tags are recommended.",
"effectiveFrom": "2026-10-01",
"effectiveTo": null,
"icon": "spark",
"id": "ai-attribution",
"impacts": [
"ai_economics",
"ai_tagging_signal"
],
"note": "No merged change in this period carries an AI signal, so the AI figures rest on nothing yet.",
"options": [
{
"label": "Keep self-reported labels and trailers",
"method": "self_reported",
"range": null,
"value": "Self-reported labels and trailers"
},
{
"label": "Use explicit AI tool tags only",
"method": "explicit_tools_only",
"range": null,
"value": "Explicit AI tool tags only"
},
{
"label": "Mark as manual review required",
"method": "manual_review",
"range": null,
"value": "Manual review required"
}
],
"range": null,
"rationale": null,
"source": "default",
"status": "needs_verification",
"title": "AI attribution",
"unitOrMethod": "self_reported",
"updatedAt": null,
"value": "Self-reported labels and trailers",
"versionId": null
},
{
"actorName": null,
"allowManual": true,
"classification": "date",
"classificationLabel": "Date range",
"dataAvailable": true,
"description": "The active report window is Oct 1 – Oct 31, 2026, inclusive.",
"effectiveFrom": "2026-10-01",
"effectiveTo": null,
"icon": "cal",
"id": "reporting-period",
"impacts": [
"reporting_interval"
],
"note": null,
"options": [
{
"label": "Use the active reporting range",
"method": "active_range",
"range": {
"end": "2026-10-31",
"start": "2026-10-01"
},
"value": "Oct 1 – Oct 31, 2026"
},
{
"label": "Use the engagement to date",
"method": "engagement_to_date",
"range": {
"end": "2026-10-31",
"start": "2026-01-01"
},
"value": "Jan 1 – Oct 31, 2026"
}
],
"range": {
"end": "2026-10-31",
"start": "2026-10-01"
},
"rationale": null,
"source": "default",
"status": "needs_verification",
"title": "Reporting period",
"unitOrMethod": "active_range",
"updatedAt": null,
"value": "Oct 1 – Oct 31, 2026",
"versionId": null
},
{
"actorName": null,
"allowManual": false,
"classification": "nominal",
"classificationLabel": "Nominal value",
"dataAvailable": true,
"description": "How the Oct 1 – Oct 31, 2026 team estimate from role bands is spread across tracked work items. Amounts stay estimates, never actual spend.",
"effectiveFrom": "2026-10-01",
"effectiveTo": null,
"icon": "gauge",
"id": "work-cost-allocation",
"impacts": [
"work_item_cost"
],
"note": null,
"options": [
{
"label": "Keep the team estimate without allocating it",
"method": "not_allocated",
"range": null,
"value": "Team estimate only"
},
{
"label": "Allocate the team estimate by story points",
"method": "points_weighted",
"range": null,
"value": "1 of 1 items pointed"
},
{
"label": "Allocate the team estimate by original time estimates",
"method": "estimate_hours_weighted",
"range": null,
"value": "0 of 1 items with time estimates"
}
],
"range": null,
"rationale": null,
"source": "default",
"status": "needs_verification",
"title": "Work-item cost allocation",
"unitOrMethod": "not_allocated",
"updatedAt": null,
"value": "Team estimate only",
"versionId": null
}
],
"period": {
"end": "2026-10-31",
"start": "2026-10-01",
"timeZone": "UTC"
},
"scope": {
"clientId": "22222222-2222-4222-8222-222222222222",
"projectId": "11111111-1111-4111-8111-111111111111"
}
}
Use IDs and versions from your own preceding responses. Replace the synthetic UUIDs, dates and names in these independent examples. Set SCOPEWORTH_API_BASE and SCOPEWORTH_API_KEY only on your server.
cURL
curl --request GET "$SCOPEWORTH_API_BASE/organizations/example-org/workspaces/example-workspace/assumptions?projectId=11111111-1111-4111-8111-111111111111&start=2026-10-01&end=2026-10-31&tz=UTC" \
--header "Authorization: Bearer $SCOPEWORTH_API_KEY"JavaScript fetch
// Run on your server. API_BASE ends in /api/v1 (combined host) or /v1 (verified cell).
const response = await fetch(process.env.SCOPEWORTH_API_BASE + "/organizations/example-org/workspaces/example-workspace/assumptions?projectId=11111111-1111-4111-8111-111111111111&start=2026-10-01&end=2026-10-31&tz=UTC", {
method: "GET",
headers: {
"Authorization": `Bearer ${process.env.SCOPEWORTH_API_KEY}`
},
});
if (!response.ok) throw new Error(`ScopeWorth refused request: ${response.status}`);
const result = await response.json();Python requests
import os, requests
headers = {"Authorization":"Bearer " + os.environ["SCOPEWORTH_API_KEY"]}
response = requests.request("GET", os.environ["SCOPEWORTH_API_BASE"] + "/organizations/example-org/workspaces/example-workspace/assumptions?projectId=11111111-1111-4111-8111-111111111111&start=2026-10-01&end=2026-10-31&tz=UTC", headers=headers, timeout=30)
response.raise_for_status()
result = response.json()For refusals, follow error recovery. A scope or plan badge is eligibility, not proof of authorization or available evidence. Read current directory IDs and versions before correcting a request. Keep an idempotency key for one unchanged mutation attempt; never blindly retry uncertain external work.
Read append-only assumption history
Operation: assumptions.history · GET /assumptions/:assumptionId/history
Read the existing append-only versions for one registry identifier and tenant scope, with author, rationale, effective interval and supersedes chain. No pagination is offered. A registry identifier names an assumption type, not a version UUID. Exact scope, current creator action/dataset access and tenant ownership apply. Identical successful retries return the original response without extra history or audit. Revisions affect applicable future/current calculations; stored source evidence and historical report snapshots are never rewritten.
Required key scope: assumptions:read. Current creator action: assumptions.read. Eligible plans: free, starter, growth, scale; legacy contracts: free, entry, growth. stable contract. These badges do not override current role, evidence window, quotas or target ownership.
-
Reporting and effective intervals are ordered; tz is a valid IANA time zone.
-
Manual values have no date range; date_range values agree with the ordered range.
-
supersedesId must match the observed current head. Current evidence/options are rechecked under the assumption lock.
-
Rationale is optional in the existing domain contract; provide a meaningful reason for traceability.
Parameters (required flags, defaults, units and bounds are the canonical schema):
View schema or synthetic response
[
{
"example": "cost-basis",
"in": "path",
"name": "assumptionId",
"required": true,
"schema": {
"enum": [
"cost-basis",
"scope-baseline",
"meeting-attribution",
"ai-attribution",
"reporting-period",
"work-cost-allocation"
],
"type": "string"
}
},
{
"in": "query",
"name": "clientId",
"required": false,
"schema": {
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)quot;,
"type": "string"
}
},
{
"example": "11111111-1111-4111-8111-111111111111",
"in": "query",
"name": "projectId",
"required": false,
"schema": {
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)quot;,
"type": "string"
}
}
]
Success statuses: 200. The JSON response is the saved/read representation. Synthetic examples below show shape, not customer evidence.
Synthetic response:
View schema or synthetic response
{
"versions": [
{
"actorName": "Example owner",
"actorUserId": "00000000-0000-4000-8000-000000000005",
"assumptionId": "cost-basis",
"clientId": "22222222-2222-4222-8222-222222222222",
"createdAt": "2026-10-01T07:48:09.127Z",
"effectiveFrom": "2026-10-01",
"effectiveTo": null,
"id": "00000000-0000-4000-8000-000000000004",
"projectId": "11111111-1111-4111-8111-111111111111",
"rationale": "Use the agreed engagement hourly rate",
"source": "manual",
"status": "rectified",
"supersedesId": null,
"unitOrMethod": "manual",
"value": "125/h"
}
]
}
Use IDs and versions from your own preceding responses. Replace the synthetic UUIDs, dates and names in these independent examples. Set SCOPEWORTH_API_BASE and SCOPEWORTH_API_KEY only on your server.
cURL
curl --request GET "$SCOPEWORTH_API_BASE/organizations/example-org/workspaces/example-workspace/assumptions/cost-basis/history?projectId=11111111-1111-4111-8111-111111111111" \
--header "Authorization: Bearer $SCOPEWORTH_API_KEY"JavaScript fetch
// Run on your server. API_BASE ends in /api/v1 (combined host) or /v1 (verified cell).
const response = await fetch(process.env.SCOPEWORTH_API_BASE + "/organizations/example-org/workspaces/example-workspace/assumptions/cost-basis/history?projectId=11111111-1111-4111-8111-111111111111", {
method: "GET",
headers: {
"Authorization": `Bearer ${process.env.SCOPEWORTH_API_KEY}`
},
});
if (!response.ok) throw new Error(`ScopeWorth refused request: ${response.status}`);
const result = await response.json();Python requests
import os, requests
headers = {"Authorization":"Bearer " + os.environ["SCOPEWORTH_API_KEY"]}
response = requests.request("GET", os.environ["SCOPEWORTH_API_BASE"] + "/organizations/example-org/workspaces/example-workspace/assumptions/cost-basis/history?projectId=11111111-1111-4111-8111-111111111111", headers=headers, timeout=30)
response.raise_for_status()
result = response.json()For refusals, follow error recovery. A scope or plan badge is eligibility, not proof of authorization or available evidence. Read current directory IDs and versions before correcting a request. Keep an idempotency key for one unchanged mutation attempt; never blindly retry uncertain external work.
Confirm the current evidenced value
Operation: assumptions.confirm · POST /assumptions/:assumptionId/confirm
Agree to the current value only when its evidence is available. Supply the observed versionId as supersedesId, or null for the original value. Missing evidence, stale version or changed options returns 409. A single-period override remains limited to that period. Confirmation appends a version and audit; it cannot invent missing evidence. Exact scope, current creator action/dataset access and tenant ownership apply. Identical successful retries return the original response without extra history or audit. Revisions affect applicable future/current calculations; stored source evidence and historical report snapshots are never rewritten.
Required key scope: assumptions:write. Current creator action: assumptions.manage. Eligible plans: free, starter, growth, scale; legacy contracts: free, entry, growth. stable contract. These badges do not override current role, evidence window, quotas or target ownership.
-
Reporting and effective intervals are ordered; tz is a valid IANA time zone.
-
Manual values have no date range; date_range values agree with the ordered range.
-
supersedesId must match the observed current head. Current evidence/options are rechecked under the assumption lock.
-
Rationale is optional in the existing domain contract; provide a meaningful reason for traceability.
Parameters (required flags, defaults, units and bounds are the canonical schema):
View schema or synthetic response
[
{
"example": "reporting-period",
"in": "path",
"name": "assumptionId",
"required": true,
"schema": {
"enum": [
"cost-basis",
"scope-baseline",
"meeting-attribution",
"ai-attribution",
"reporting-period",
"work-cost-allocation"
],
"type": "string"
}
},
{
"example": "example-assumptions.confirm",
"in": "header",
"name": "idempotency-key",
"required": true,
"schema": {
"pattern": "^[\\x21-\\x7e]{1,200}quot;,
"type": "string"
}
}
]
Request body schema:
View schema or synthetic response
{
"content": {
"application/json": {
"examples": {
"synthetic1": {
"value": {
"end": "2026-10-31",
"projectId": "11111111-1111-4111-8111-111111111111",
"rationale": "Confirm the agreed reporting window",
"start": "2026-10-01",
"supersedesId": null,
"tz": "UTC"
}
}
},
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"clientId": {
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)quot;,
"type": "string"
},
"end": {
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))quot;,
"type": "string"
},
"projectId": {
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)quot;,
"type": "string"
},
"rationale": {
"maxLength": 1000,
"type": "string"
},
"start": {
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))quot;,
"type": "string"
},
"supersedesId": {
"anyOf": [
{
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)quot;,
"type": "string"
},
{
"type": "null"
}
],
"default": null
},
"tz": {
"maxLength": 64,
"minLength": 1,
"type": "string"
}
},
"required": [
"start",
"end",
"tz"
],
"type": "object"
}
}
},
"required": true
}
Success statuses: 200. The JSON response is the saved/read representation. Synthetic examples below show shape, not customer evidence.
Synthetic response:
View schema or synthetic response
{
"canWrite": true,
"coverage": {
"completenessPct": 17,
"freshestAt": "2026-10-01T07:48:09.083Z",
"settled": 1,
"stalestAt": "2026-10-01T07:48:09.083Z",
"stalestDays": 0,
"total": 6
},
"entries": [
{
"actorName": null,
"allowManual": true,
"classification": "financial",
"classificationLabel": "Financial value",
"dataAvailable": true,
"description": "Role-based blended rate used to estimate Oct 1 – Oct 31, 2026 delivery investment. Per-engineer rates would lift precision.",
"effectiveFrom": "2026-10-01",
"effectiveTo": null,
"icon": "coin",
"id": "cost-basis",
"impacts": [
"period_spend",
"invoice_defense"
],
"note": null,
"options": [
{
"label": "Keep per-person rates, role rates otherwise",
"method": "person_then_role",
"range": null,
"value": "$165/h"
}
],
"range": null,
"rationale": null,
"source": "default",
"status": "needs_verification",
"title": "Cost estimate basis",
"unitOrMethod": "person_then_role",
"updatedAt": null,
"value": "$165/h",
"versionId": null
},
{
"actorName": null,
"allowManual": false,
"classification": "quantity",
"classificationLabel": "Quantity",
"dataAvailable": true,
"description": "Items added after the Jan 1, 2026 scope lock count as scope expansion for this report.",
"effectiveFrom": "2026-10-01",
"effectiveTo": null,
"icon": "check",
"id": "scope-baseline",
"impacts": [
"scope_valuation"
],
"note": null,
"options": [
{
"label": "Keep the engagement start as the scope lock",
"method": "engagement_start",
"range": null,
"value": "1 work items"
},
{
"label": "Use the reporting period start",
"method": "period_start",
"range": null,
"value": "3 work items"
}
],
"range": null,
"rationale": null,
"source": "default",
"status": "needs_verification",
"title": "Scope baseline",
"unitOrMethod": "engagement_start",
"updatedAt": null,
"value": "1 work items",
"versionId": null
},
{
"actorName": null,
"allowManual": false,
"classification": "percentage",
"classificationLabel": "Percentage",
"dataAvailable": false,
"description": "Calendar events with explicit project tags only. Untagged meetings are excluded from the coordination estimate.",
"effectiveFrom": "2026-10-01",
"effectiveTo": null,
"icon": "gauge",
"id": "meeting-attribution",
"impacts": [
"coordination_cost"
],
"note": "No calendar events were synced for this period, so coordination cost is counted from nothing.",
"options": [
{
"label": "Keep meetings tagged to this project",
"method": "project_tagged",
"range": null,
"value": "No meetings synced"
}
],
"range": null,
"rationale": null,
"source": "default",
"status": "needs_verification",
"title": "Meeting attribution",
"unitOrMethod": "project_tagged",
"updatedAt": null,
"value": "No meetings synced",
"versionId": null
},
{
"actorName": null,
"allowManual": false,
"classification": "nominal",
"classificationLabel": "Nominal value",
"dataAvailable": false,
"description": "Uses self-reported labels and trailers to identify AI-assisted changes. Explicit AI tags are recommended.",
"effectiveFrom": "2026-10-01",
"effectiveTo": null,
"icon": "spark",
"id": "ai-attribution",
"impacts": [
"ai_economics",
"ai_tagging_signal"
],
"note": "No merged change in this period carries an AI signal, so the AI figures rest on nothing yet.",
"options": [
{
"label": "Keep self-reported labels and trailers",
"method": "self_reported",
"range": null,
"value": "Self-reported labels and trailers"
},
{
"label": "Use explicit AI tool tags only",
"method": "explicit_tools_only",
"range": null,
"value": "Explicit AI tool tags only"
},
{
"label": "Mark as manual review required",
"method": "manual_review",
"range": null,
"value": "Manual review required"
}
],
"range": null,
"rationale": null,
"source": "default",
"status": "needs_verification",
"title": "AI attribution",
"unitOrMethod": "self_reported",
"updatedAt": null,
"value": "Self-reported labels and trailers",
"versionId": null
},
{
"actorName": null,
"allowManual": true,
"classification": "date",
"classificationLabel": "Date range",
"dataAvailable": true,
"description": "The active report window is Oct 1 – Oct 31, 2026, inclusive.",
"effectiveFrom": "2026-10-01",
"effectiveTo": null,
"icon": "cal",
"id": "reporting-period",
"impacts": [
"reporting_interval"
],
"note": null,
"options": [
{
"label": "Use the active reporting range",
"method": "active_range",
"range": {
"end": "2026-10-31",
"start": "2026-10-01"
},
"value": "Oct 1 – Oct 31, 2026"
},
{
"label": "Use the engagement to date",
"method": "engagement_to_date",
"range": {
"end": "2026-10-31",
"start": "2026-01-01"
},
"value": "Jan 1 – Oct 31, 2026"
}
],
"range": {
"end": "2026-10-31",
"start": "2026-10-01"
},
"rationale": "Confirm the agreed reporting window",
"source": "default",
"status": "confirmed",
"title": "Reporting period",
"unitOrMethod": "active_range",
"updatedAt": "2026-10-01T07:48:09.083Z",
"value": "Oct 1 – Oct 31, 2026",
"versionId": "00000000-0000-4000-8000-000000000003"
},
{
"actorName": null,
"allowManual": false,
"classification": "nominal",
"classificationLabel": "Nominal value",
"dataAvailable": true,
"description": "How the Oct 1 – Oct 31, 2026 team estimate from role bands is spread across tracked work items. Amounts stay estimates, never actual spend.",
"effectiveFrom": "2026-10-01",
"effectiveTo": null,
"icon": "gauge",
"id": "work-cost-allocation",
"impacts": [
"work_item_cost"
],
"note": null,
"options": [
{
"label": "Keep the team estimate without allocating it",
"method": "not_allocated",
"range": null,
"value": "Team estimate only"
},
{
"label": "Allocate the team estimate by story points",
"method": "points_weighted",
"range": null,
"value": "1 of 1 items pointed"
},
{
"label": "Allocate the team estimate by original time estimates",
"method": "estimate_hours_weighted",
"range": null,
"value": "0 of 1 items with time estimates"
}
],
"range": null,
"rationale": null,
"source": "default",
"status": "needs_verification",
"title": "Work-item cost allocation",
"unitOrMethod": "not_allocated",
"updatedAt": null,
"value": "Team estimate only",
"versionId": null
}
],
"period": {
"end": "2026-10-31",
"start": "2026-10-01",
"timeZone": "UTC"
},
"scope": {
"clientId": "22222222-2222-4222-8222-222222222222",
"projectId": "11111111-1111-4111-8111-111111111111"
}
}
Use IDs and versions from your own preceding responses. Replace the synthetic UUIDs, dates and names in these independent examples. Set SCOPEWORTH_API_BASE and SCOPEWORTH_API_KEY only on your server.
cURL
curl --request POST "$SCOPEWORTH_API_BASE/organizations/example-org/workspaces/example-workspace/assumptions/reporting-period/confirm" \
--header "Authorization: Bearer $SCOPEWORTH_API_KEY" \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: example-operation-attempt-1' \
--data-raw '{"projectId":"11111111-1111-4111-8111-111111111111","start":"2026-10-01","end":"2026-10-31","tz":"UTC","supersedesId":null,"rationale":"Confirm the agreed reporting window"}'JavaScript fetch
// Run on your server. API_BASE ends in /api/v1 (combined host) or /v1 (verified cell).
const response = await fetch(process.env.SCOPEWORTH_API_BASE + "/organizations/example-org/workspaces/example-workspace/assumptions/reporting-period/confirm", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.SCOPEWORTH_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": "example-operation-attempt-1"
},
body: JSON.stringify({
"projectId": "11111111-1111-4111-8111-111111111111",
"start": "2026-10-01",
"end": "2026-10-31",
"tz": "UTC",
"supersedesId": null,
"rationale": "Confirm the agreed reporting window"
}),
});
if (!response.ok) throw new Error(`ScopeWorth refused request: ${response.status}`);
const result = await response.json();Python requests
import os, requests
headers = {"Authorization":"Bearer " + os.environ["SCOPEWORTH_API_KEY"],"Content-Type":"application/json","Idempotency-Key":"example-operation-attempt-1"}
response = requests.request("POST", os.environ["SCOPEWORTH_API_BASE"] + "/organizations/example-org/workspaces/example-workspace/assumptions/reporting-period/confirm", headers=headers, json=__import__("json").loads("{\"projectId\":\"11111111-1111-4111-8111-111111111111\",\"start\":\"2026-10-01\",\"end\":\"2026-10-31\",\"tz\":\"UTC\",\"supersedesId\":null,\"rationale\":\"Confirm the agreed reporting window\"}"), timeout=30)
response.raise_for_status()
result = response.json()For refusals, follow error recovery. A scope or plan badge is eligibility, not proof of authorization or available evidence. Read current directory IDs and versions before correcting a request. Keep an idempotency key for one unchanged mutation attempt; never blindly retry uncertain external work.
Confirm only the reviewed current version with the required creator action.
Correct an assumption with a stated basis
Operation: assumptions.rectify · POST /assumptions/:assumptionId/rectify
Append a correction using an offered option, a manual value or a date_range. Manual values cannot carry range; date_range needs ordered boundaries and the exact shared formatted value. Hourly rates must match the engagement currency; allocation basis must use an offered option. Options are revalidated against current evidence. appliesTo chooses a default or this-period override; do not combine it with explicit effective bounds. Existing override carry-forward semantics and rationale remain unchanged. Exact scope, current creator action/dataset access and tenant ownership apply. Identical successful retries return the original response without extra history or audit. Revisions affect applicable future/current calculations; stored source evidence and historical report snapshots are never rewritten.
Required key scope: assumptions:write. Current creator action: assumptions.manage. Eligible plans: free, starter, growth, scale; legacy contracts: free, entry, growth. stable contract. These badges do not override current role, evidence window, quotas or target ownership.
-
Reporting and effective intervals are ordered; tz is a valid IANA time zone.
-
Manual values have no date range; date_range values agree with the ordered range.
-
supersedesId must match the observed current head. Current evidence/options are rechecked under the assumption lock.
-
Rationale is optional in the existing domain contract; provide a meaningful reason for traceability.
Parameters (required flags, defaults, units and bounds are the canonical schema):
View schema or synthetic response
[
{
"example": "cost-basis",
"in": "path",
"name": "assumptionId",
"required": true,
"schema": {
"enum": [
"cost-basis",
"scope-baseline",
"meeting-attribution",
"ai-attribution",
"reporting-period",
"work-cost-allocation"
],
"type": "string"
}
},
{
"example": "example-assumptions.rectify",
"in": "header",
"name": "idempotency-key",
"required": true,
"schema": {
"pattern": "^[\\x21-\\x7e]{1,200}quot;,
"type": "string"
}
}
]
Request body schema:
View schema or synthetic response
{
"content": {
"application/json": {
"examples": {
"synthetic1": {
"value": {
"end": "2026-10-31",
"projectId": "11111111-1111-4111-8111-111111111111",
"rationale": "Use the agreed engagement hourly rate",
"source": "manual",
"start": "2026-10-01",
"supersedesId": null,
"tz": "UTC",
"value": "125/h"
}
}
},
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"appliesTo": {
"enum": [
"every_period",
"period_only",
"from_period"
],
"type": "string"
},
"clientId": {
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)quot;,
"type": "string"
},
"effectiveFrom": {
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))quot;,
"type": "string"
},
"effectiveTo": {
"anyOf": [
{
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))quot;,
"type": "string"
},
{
"type": "null"
}
]
},
"end": {
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))quot;,
"type": "string"
},
"method": {
"maxLength": 80,
"minLength": 1,
"type": "string"
},
"projectId": {
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)quot;,
"type": "string"
},
"range": {
"properties": {
"end": {
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))quot;,
"type": "string"
},
"start": {
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))quot;,
"type": "string"
}
},
"required": [
"start",
"end"
],
"type": "object"
},
"rationale": {
"maxLength": 1000,
"type": "string"
},
"source": {
"enum": [
"option",
"manual",
"date_range"
],
"type": "string"
},
"start": {
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))quot;,
"type": "string"
},
"supersedesId": {
"anyOf": [
{
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)quot;,
"type": "string"
},
{
"type": "null"
}
],
"default": null
},
"tz": {
"maxLength": 64,
"minLength": 1,
"type": "string"
},
"value": {
"maxLength": 200,
"minLength": 1,
"type": "string"
}
},
"required": [
"start",
"end",
"tz",
"value",
"source"
],
"type": "object"
}
}
},
"required": true
}
Success statuses: 200. The JSON response is the saved/read representation. Synthetic examples below show shape, not customer evidence.
Synthetic response:
View schema or synthetic response
{
"canWrite": true,
"coverage": {
"completenessPct": 33,
"freshestAt": "2026-10-01T07:48:09.127Z",
"settled": 2,
"stalestAt": "2026-10-01T07:48:09.083Z",
"stalestDays": 0,
"total": 6
},
"entries": [
{
"actorName": null,
"allowManual": true,
"classification": "financial",
"classificationLabel": "Financial value",
"dataAvailable": true,
"description": "Role-based blended rate used to estimate Oct 1 – Oct 31, 2026 delivery investment. Per-engineer rates would lift precision.",
"effectiveFrom": "2026-10-01",
"effectiveTo": null,
"icon": "coin",
"id": "cost-basis",
"impacts": [
"period_spend",
"invoice_defense"
],
"note": null,
"options": [
{
"label": "Keep per-person rates, role rates otherwise",
"method": "person_then_role",
"range": null,
"value": "$165/h"
}
],
"range": null,
"rationale": "Use the agreed engagement hourly rate",
"source": "manual",
"status": "rectified",
"title": "Cost estimate basis",
"unitOrMethod": "manual",
"updatedAt": "2026-10-01T07:48:09.127Z",
"value": "125/h",
"versionId": "00000000-0000-4000-8000-000000000004"
},
{
"actorName": null,
"allowManual": false,
"classification": "quantity",
"classificationLabel": "Quantity",
"dataAvailable": true,
"description": "Items added after the Jan 1, 2026 scope lock count as scope expansion for this report.",
"effectiveFrom": "2026-10-01",
"effectiveTo": null,
"icon": "check",
"id": "scope-baseline",
"impacts": [
"scope_valuation"
],
"note": null,
"options": [
{
"label": "Keep the engagement start as the scope lock",
"method": "engagement_start",
"range": null,
"value": "1 work items"
},
{
"label": "Use the reporting period start",
"method": "period_start",
"range": null,
"value": "3 work items"
}
],
"range": null,
"rationale": null,
"source": "default",
"status": "needs_verification",
"title": "Scope baseline",
"unitOrMethod": "engagement_start",
"updatedAt": null,
"value": "1 work items",
"versionId": null
},
{
"actorName": null,
"allowManual": false,
"classification": "percentage",
"classificationLabel": "Percentage",
"dataAvailable": false,
"description": "Calendar events with explicit project tags only. Untagged meetings are excluded from the coordination estimate.",
"effectiveFrom": "2026-10-01",
"effectiveTo": null,
"icon": "gauge",
"id": "meeting-attribution",
"impacts": [
"coordination_cost"
],
"note": "No calendar events were synced for this period, so coordination cost is counted from nothing.",
"options": [
{
"label": "Keep meetings tagged to this project",
"method": "project_tagged",
"range": null,
"value": "No meetings synced"
}
],
"range": null,
"rationale": null,
"source": "default",
"status": "needs_verification",
"title": "Meeting attribution",
"unitOrMethod": "project_tagged",
"updatedAt": null,
"value": "No meetings synced",
"versionId": null
},
{
"actorName": null,
"allowManual": false,
"classification": "nominal",
"classificationLabel": "Nominal value",
"dataAvailable": false,
"description": "Uses self-reported labels and trailers to identify AI-assisted changes. Explicit AI tags are recommended.",
"effectiveFrom": "2026-10-01",
"effectiveTo": null,
"icon": "spark",
"id": "ai-attribution",
"impacts": [
"ai_economics",
"ai_tagging_signal"
],
"note": "No merged change in this period carries an AI signal, so the AI figures rest on nothing yet.",
"options": [
{
"label": "Keep self-reported labels and trailers",
"method": "self_reported",
"range": null,
"value": "Self-reported labels and trailers"
},
{
"label": "Use explicit AI tool tags only",
"method": "explicit_tools_only",
"range": null,
"value": "Explicit AI tool tags only"
},
{
"label": "Mark as manual review required",
"method": "manual_review",
"range": null,
"value": "Manual review required"
}
],
"range": null,
"rationale": null,
"source": "default",
"status": "needs_verification",
"title": "AI attribution",
"unitOrMethod": "self_reported",
"updatedAt": null,
"value": "Self-reported labels and trailers",
"versionId": null
},
{
"actorName": null,
"allowManual": true,
"classification": "date",
"classificationLabel": "Date range",
"dataAvailable": true,
"description": "The active report window is Oct 1 – Oct 31, 2026, inclusive.",
"effectiveFrom": "2026-10-01",
"effectiveTo": null,
"icon": "cal",
"id": "reporting-period",
"impacts": [
"reporting_interval"
],
"note": null,
"options": [
{
"label": "Use the active reporting range",
"method": "active_range",
"range": {
"end": "2026-10-31",
"start": "2026-10-01"
},
"value": "Oct 1 – Oct 31, 2026"
},
{
"label": "Use the engagement to date",
"method": "engagement_to_date",
"range": {
"end": "2026-10-31",
"start": "2026-01-01"
},
"value": "Jan 1 – Oct 31, 2026"
}
],
"range": {
"end": "2026-10-31",
"start": "2026-10-01"
},
"rationale": "Confirm the agreed reporting window",
"source": "default",
"status": "confirmed",
"title": "Reporting period",
"unitOrMethod": "active_range",
"updatedAt": "2026-10-01T07:48:09.083Z",
"value": "Oct 1 – Oct 31, 2026",
"versionId": "00000000-0000-4000-8000-000000000003"
},
{
"actorName": null,
"allowManual": false,
"classification": "nominal",
"classificationLabel": "Nominal value",
"dataAvailable": true,
"description": "How the Oct 1 – Oct 31, 2026 team estimate from role bands is spread across tracked work items. Amounts stay estimates, never actual spend.",
"effectiveFrom": "2026-10-01",
"effectiveTo": null,
"icon": "gauge",
"id": "work-cost-allocation",
"impacts": [
"work_item_cost"
],
"note": null,
"options": [
{
"label": "Keep the team estimate without allocating it",
"method": "not_allocated",
"range": null,
"value": "Team estimate only"
},
{
"label": "Allocate the team estimate by story points",
"method": "points_weighted",
"range": null,
"value": "1 of 1 items pointed"
},
{
"label": "Allocate the team estimate by original time estimates",
"method": "estimate_hours_weighted",
"range": null,
"value": "0 of 1 items with time estimates"
}
],
"range": null,
"rationale": null,
"source": "default",
"status": "needs_verification",
"title": "Work-item cost allocation",
"unitOrMethod": "not_allocated",
"updatedAt": null,
"value": "Team estimate only",
"versionId": null
}
],
"period": {
"end": "2026-10-31",
"start": "2026-10-01",
"timeZone": "UTC"
},
"scope": {
"clientId": "22222222-2222-4222-8222-222222222222",
"projectId": "11111111-1111-4111-8111-111111111111"
}
}
Use IDs and versions from your own preceding responses. Replace the synthetic UUIDs, dates and names in these independent examples. Set SCOPEWORTH_API_BASE and SCOPEWORTH_API_KEY only on your server.
cURL
curl --request POST "$SCOPEWORTH_API_BASE/organizations/example-org/workspaces/example-workspace/assumptions/cost-basis/rectify" \
--header "Authorization: Bearer $SCOPEWORTH_API_KEY" \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: example-operation-attempt-1' \
--data-raw '{"projectId":"11111111-1111-4111-8111-111111111111","start":"2026-10-01","end":"2026-10-31","tz":"UTC","value":"125/h","source":"manual","supersedesId":null,"rationale":"Use the agreed engagement hourly rate"}'JavaScript fetch
// Run on your server. API_BASE ends in /api/v1 (combined host) or /v1 (verified cell).
const response = await fetch(process.env.SCOPEWORTH_API_BASE + "/organizations/example-org/workspaces/example-workspace/assumptions/cost-basis/rectify", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.SCOPEWORTH_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": "example-operation-attempt-1"
},
body: JSON.stringify({
"projectId": "11111111-1111-4111-8111-111111111111",
"start": "2026-10-01",
"end": "2026-10-31",
"tz": "UTC",
"value": "125/h",
"source": "manual",
"supersedesId": null,
"rationale": "Use the agreed engagement hourly rate"
}),
});
if (!response.ok) throw new Error(`ScopeWorth refused request: ${response.status}`);
const result = await response.json();Python requests
import os, requests
headers = {"Authorization":"Bearer " + os.environ["SCOPEWORTH_API_KEY"],"Content-Type":"application/json","Idempotency-Key":"example-operation-attempt-1"}
response = requests.request("POST", os.environ["SCOPEWORTH_API_BASE"] + "/organizations/example-org/workspaces/example-workspace/assumptions/cost-basis/rectify", headers=headers, json=__import__("json").loads("{\"projectId\":\"11111111-1111-4111-8111-111111111111\",\"start\":\"2026-10-01\",\"end\":\"2026-10-31\",\"tz\":\"UTC\",\"value\":\"125/h\",\"source\":\"manual\",\"supersedesId\":null,\"rationale\":\"Use the agreed engagement hourly rate\"}"), timeout=30)
response.raise_for_status()
result = response.json()For refusals, follow error recovery. A scope or plan badge is eligibility, not proof of authorization or available evidence. Read current directory IDs and versions before correcting a request. Keep an idempotency key for one unchanged mutation attempt; never blindly retry uncertain external work.
Rectification appends an audited version with a reason and validated value. Preserve period/timezone semantics and schema currency/rate units. A stale version requires a new read and decision. Historical audit is retained; existing frozen packages/snapshots do not change.
Continue with investigations and reports.