Schema: phase.milestone_release gains required repo_hub/repo_hub_uri/
repo_id/repo_name; phase gains optional base_phase_id. Backfilled the
golden phase-001 fixture (placeholder values, it's synthetic) and the
three real pilot-candidate manifests with actual Forgejo repo ids
confirmed live (net-kingdom=67, vergabe-teilnahme=62,
info-tech-canon=47, all coulomb/*).
Discovered along the way: the schema change alone would have broken
the existing Control Plane registration form, since nothing collected
the four new fields. Fixed inline rather than leaving it broken
between tasks -- this also completes T04's ledger UI change (drop the
hand-typed ledger input, auto-compute /phases/{id}/ledger, add a
drill-down reference link on phase_detail.html) since both changes
touch the same form/route.
Full suite: 94 passing offline (was 84), 158 passing with Docker
(was 146).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
133 lines
5.3 KiB
JSON
133 lines
5.3 KiB
JSON
{
|
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
"$id": "https://target-revenue.example/schemas/phase_manifest.schema.json",
|
|
"title": "Phase Manifest",
|
|
"description": "Stage 0 schema per specs/TechnicalSpecificationDocument.md §3.1 and specs/OpenQuestions-WorkingDefaults.md Q3/Q6/Q8. Field names and semantics are authoritative from specs/TargetRevenueLicenseConcept.md §16.",
|
|
"type": "object",
|
|
"required": ["framework", "license", "phase"],
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"framework": {
|
|
"type": "string",
|
|
"description": "Framework version tag, e.g. TRF-0.1."
|
|
},
|
|
"license": {
|
|
"type": "string",
|
|
"description": "TRSL version tag, e.g. TRSL-0.1."
|
|
},
|
|
"phase": {
|
|
"type": "object",
|
|
"required": [
|
|
"id",
|
|
"milestone_release",
|
|
"initial_target",
|
|
"future_license",
|
|
"degeneration_policy",
|
|
"longstop_at",
|
|
"ledger"
|
|
],
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"id": {
|
|
"type": "string",
|
|
"pattern": "^trsl:phase:[a-zA-Z0-9._-]+$",
|
|
"description": "Globally unique, immutable once published."
|
|
},
|
|
"milestone_release": {
|
|
"type": "object",
|
|
"required": ["name", "source_revision", "repo_hub", "repo_hub_uri", "repo_id", "repo_name"],
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"name": { "type": "string" },
|
|
"source_revision": { "type": "string" },
|
|
"artifact_sha256": {
|
|
"type": "string",
|
|
"pattern": "^[a-f0-9]{64}$",
|
|
"description": "Recommended; required if a built artifact (not just source) is governed."
|
|
},
|
|
"repo_hub": {
|
|
"type": "string",
|
|
"pattern": "^[a-z0-9-]+$",
|
|
"description": "Stable, human-assigned slug for the Forgejo instance hosting this repo, e.g. \"forgejo-coulomb\". Minted by this project, not read from Forgejo (no instance-level identity endpoint exists)."
|
|
},
|
|
"repo_hub_uri": {
|
|
"type": "string",
|
|
"format": "uri",
|
|
"description": "The Forgejo service's current base URL, e.g. \"https://forgejo.coulomb.social\". Retained alongside repo_hub (not derived from it) so a domain change stays repairable."
|
|
},
|
|
"repo_id": {
|
|
"type": "integer",
|
|
"minimum": 1,
|
|
"description": "Forgejo's own internal numeric repo id (GET /api/v1/repos/{owner}/{repo} -> id). Stable across repo renames, unlike repo_name."
|
|
},
|
|
"repo_name": {
|
|
"type": "string",
|
|
"pattern": "^[\\w.-]+/[\\w.-]+$",
|
|
"description": "\"owner/repo\" slug at time of Phase registration. Human-readable; repo_id is authoritative if this ever diverges after a rename."
|
|
}
|
|
}
|
|
},
|
|
"initial_target": {
|
|
"type": "object",
|
|
"required": ["amount", "currency"],
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"amount": { "type": "number", "exclusiveMinimum": 0 },
|
|
"currency": {
|
|
"type": "string",
|
|
"pattern": "^[A-Z]{3}$",
|
|
"description": "ISO 4217 code. Working default Q6: one native currency per Phase."
|
|
}
|
|
}
|
|
},
|
|
"target_basis": {
|
|
"type": "object",
|
|
"description": "Recommended transparency metadata (working default Q5), not legally required.",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"estimated_effort_days": { "type": "number", "minimum": 0 },
|
|
"daily_rate": { "type": "number", "minimum": 0 },
|
|
"approved_direct_costs": { "type": "number", "minimum": 0 },
|
|
"target_multiple": {
|
|
"type": "number",
|
|
"minimum": 0,
|
|
"description": "Open decimal per working default Q4. Guidance classes {0,1,10,100,1000} are not a closed enum."
|
|
}
|
|
}
|
|
},
|
|
"future_license": {
|
|
"type": "string",
|
|
"enum": ["MIT", "Apache-2.0"],
|
|
"description": "Working default Q3: closed enum for Stage 0."
|
|
},
|
|
"degeneration_policy": {
|
|
"type": "string",
|
|
"pattern": "^trsl:policy:[a-zA-Z0-9._-]+@[0-9]+(\\.[0-9]+)*$",
|
|
"description": "e.g. trsl:policy:linear-longstop-v0@1.0 (working default Q7)."
|
|
},
|
|
"longstop_at": {
|
|
"type": "string",
|
|
"format": "date-time",
|
|
"description": "Required for Stage 0 per working default Q8. Full-remission / maximum-protection instant."
|
|
},
|
|
"ledger": {
|
|
"type": "string",
|
|
"description": "URL or relative path URI to the authoritative Target Ledger for this Phase."
|
|
},
|
|
"base_phase_id": {
|
|
"type": "string",
|
|
"pattern": "^trsl:phase:[a-zA-Z0-9._-]+$",
|
|
"description": "The prior Phase this one succeeds (FR-11, Rule 7). Absent for a repo's first-ever Phase; no sentinel value is used."
|
|
}
|
|
}
|
|
},
|
|
"extensions": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string",
|
|
"pattern": "^trsl:extension:[a-zA-Z0-9._-]+@[0-9]+(\\.[0-9]+)*$"
|
|
},
|
|
"description": "Optional. Applicable monetization profiles/extensions for this Phase."
|
|
}
|
|
}
|
|
}
|