docs: complete repository rename operator handoff
Assistant: codex Assistant-Model: gpt-5.6-sol Assistant-Session: 01a049a4-ee9f-78e1-9d66-2cb0f9bea3e3
This commit is contained in:
parent
0ec5b9a98d
commit
f7402bd711
11 changed files with 735 additions and 10 deletions
43
docs/examples/repository-rename-handoff-v1.json
Normal file
43
docs/examples/repository-rename-handoff-v1.json
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"schema_version": "state-hub.repository-rename-handoff.v1",
|
||||
"handoff_id": "FABRIC-WP-0042-T03",
|
||||
"operation_id": "11111111-1111-4111-8111-111111111111",
|
||||
"renamed_repository_id": "22222222-2222-4222-8222-222222222222",
|
||||
"source_repository": "railiance-fabric",
|
||||
"old_slug": "old-repository",
|
||||
"new_slug": "new-repository",
|
||||
"surface": "fabric-projection",
|
||||
"affected": {
|
||||
"paths": [
|
||||
"graph/repositories.yaml"
|
||||
],
|
||||
"graph_ids": [
|
||||
"repo:old-repository"
|
||||
]
|
||||
},
|
||||
"required_reingest": {
|
||||
"required": true,
|
||||
"procedure": "Run the owning repository's documented fabric import after committing the canonical slug.",
|
||||
"expected_source_revision": "0123456789abcdef0123456789abcdef01234567"
|
||||
},
|
||||
"verification": [
|
||||
{
|
||||
"check": "Canonical repository node is projected from the owning source revision.",
|
||||
"expected": "repo:new-repository resolves to the unchanged State Hub repository UUID",
|
||||
"evidence_ref": "docs/evidence/repository-rename-fabric-verification.json"
|
||||
},
|
||||
{
|
||||
"check": "Historical graph evidence remains queryable.",
|
||||
"expected": "Prior repo:old-repository observations remain historical evidence",
|
||||
"evidence_ref": null
|
||||
}
|
||||
],
|
||||
"owning_work_record": {
|
||||
"repository": "railiance-fabric",
|
||||
"workplan_id": "FABRIC-WP-0042",
|
||||
"task_id": "FABRIC-WP-0042-T03"
|
||||
},
|
||||
"status": "open",
|
||||
"evidence": [],
|
||||
"sensitive_data_prohibited": true
|
||||
}
|
||||
332
docs/repository-rename-operations.md
Normal file
332
docs/repository-rename-operations.md
Normal file
|
|
@ -0,0 +1,332 @@
|
|||
# Repository rename operations
|
||||
|
||||
This is the operator runbook for a lineage-preserving repository rename within
|
||||
one Forgejo instance and owner. It coordinates State Hub, Forgejo, HelixForge,
|
||||
and repository-owned work without changing the repository UUID or Forge numeric
|
||||
ID. It does not authorize a live rename; the target repository's reviewed
|
||||
migration workplan and a human cutover decision do that.
|
||||
|
||||
The identity and failure contract is
|
||||
[`ADR-001`](adr/ADR-001-repository-rename-identity-contract.md). The automated
|
||||
recovery proof is
|
||||
[`STATE-WP-0085-T07`](evidence/STATE-WP-0085-T07-repository-rename-recovery-matrix.md).
|
||||
|
||||
## Ownership
|
||||
|
||||
| Owner | Owns | Must not do |
|
||||
| --- | --- | --- |
|
||||
| State Hub | Repository UUID, canonical slug, protected aliases, verified Forge identity, operation journal, continuity verification, lifecycle events | Rename Forgejo directly, rewrite another repository's source, or register a replacement repository |
|
||||
| Forgejo | Git repository, numeric repository ID, canonical Forge name, Git data, redirects and Forge-owned settings | Decide State Hub UUID/alias history or consumer completion |
|
||||
| HelixForge/operator | Cutover window, credentials routed through their approved custodian, Forgejo rename call, pause/continue/rollback decision, destructive cleanup approval | Put credentials in CLI arguments, evidence, Git, State Hub, or chat |
|
||||
| Target repository | Repository-native migration plan, product/runtime naming decisions, source updates, fresh clone, file-first work records, aggregation of owned handoff evidence | Claim another repository's source change complete |
|
||||
| External source repository | Its own CI, deployment, policy, fabric, SBOM, credential-route, package, or documentation source and its live handoff work record | Let the target repository edit or close that obligation on its behalf |
|
||||
|
||||
Forgejo credentials are never accepted by `statehub repo rename`. Resolve
|
||||
credential ownership before the window with `warden route find` and use the
|
||||
operator-approved Forgejo/HelixForge mechanism outside State Hub. Examples below
|
||||
use identifiers and placeholder paths only.
|
||||
|
||||
## Choose the scope before planning
|
||||
|
||||
### Repository-only rename checklist
|
||||
|
||||
Use this when the Git repository coordinate changes but the product/runtime
|
||||
identity does not.
|
||||
|
||||
- [ ] Forgejo repository name and canonical clone/web URL change.
|
||||
- [ ] State Hub canonical slug changes on the existing UUID; old slug remains a
|
||||
protected alias.
|
||||
- [ ] Local checkout and automation checkout coordinates are re-registered.
|
||||
- [ ] Repository metadata and intentional live source references are updated.
|
||||
- [ ] Consumers that name the Git coordinate receive owned handoffs.
|
||||
- [ ] Binary, module/import path, API names, environment variables, Kubernetes
|
||||
namespace/services, packages/images, policy vocabulary, and telemetry labels
|
||||
explicitly remain unchanged.
|
||||
|
||||
### Product/runtime rename checklist
|
||||
|
||||
Use this only when separate product decisions authorize broader changes. Treat
|
||||
each item as independently deployable and independently reversible.
|
||||
|
||||
- [ ] Record keep/rename decisions for binary and module/import path.
|
||||
- [ ] Record compatibility policy for APIs, CLI names, environment variables,
|
||||
configuration keys, policy vocabulary, and user-facing names.
|
||||
- [ ] Plan package/image coordinates, releases, redirects, and deprecation
|
||||
windows without assuming Forge redirects cover registries.
|
||||
- [ ] Plan Kubernetes namespace, Service/DNS, Helm chart/release, secrets paths,
|
||||
dashboards, alerts, and telemetry labels.
|
||||
- [ ] Give each owning repository/platform a live workplan/task handoff.
|
||||
- [ ] Define deployment order, compatibility window, rollback boundary, and
|
||||
irreversible migrations separately from the repository rename.
|
||||
|
||||
A repository-only approval never implies the product/runtime checklist.
|
||||
|
||||
## Prepare the operation
|
||||
|
||||
1. Generate and review the target-owned adoption plan:
|
||||
|
||||
```text
|
||||
statehub repo rename generate-workplan <old-slug> <new-slug> --json
|
||||
```
|
||||
|
||||
2. Secure all branches, tags, and local changes to Forgejo. Capture the State
|
||||
Hub repository UUID, Forge numeric ID, default branch, and head commit.
|
||||
3. Inventory every slug-bearing source. Create one live handoff record in each
|
||||
owning repository using the format below. Unknown ownership is a blocker.
|
||||
4. Resolve or deliberately coordinate active work and drain/replay edge outbox
|
||||
writes. A queued receipt is not central evidence.
|
||||
5. Choose a client-owned operation UUID and keep it for every retry:
|
||||
|
||||
```text
|
||||
<operation-id> = <uuid-generated-by-operator-or-orchestrator>
|
||||
<confirmation> = rename:<state-hub-repository-uuid>:<old-slug>:<new-slug>
|
||||
```
|
||||
|
||||
6. Capture a new preflight immediately before the window. The output file is
|
||||
private and single-use; do not commit it:
|
||||
|
||||
```text
|
||||
statehub repo rename preflight <old-slug> <new-slug> \
|
||||
--operation-id <operation-id> \
|
||||
--output <private-mode-0600-preflight.json> --json
|
||||
```
|
||||
|
||||
Proceed only when `ok` and `result.safe_to_apply` are true, `blockers` is empty,
|
||||
the immutable IDs/head match the approved baseline, and every warning has a
|
||||
recorded disposition.
|
||||
|
||||
## Execute one phase at a time
|
||||
|
||||
Start the durable journal before asking HelixForge to mutate Forgejo:
|
||||
|
||||
```text
|
||||
statehub repo rename start <old-slug> <new-slug> \
|
||||
--operation-id <operation-id> \
|
||||
--preflight-file <private-mode-0600-preflight.json> \
|
||||
--actor <operator-id> --confirm '<confirmation>' --json
|
||||
```
|
||||
|
||||
The operation is now `preflighted`. Apply only the phase named by
|
||||
`next_safe_action`:
|
||||
|
||||
```text
|
||||
statehub repo rename apply <operation-id> --phase forge-renamed \
|
||||
--confirm '<confirmation>' --json
|
||||
statehub repo rename apply <operation-id> --phase statehub-rebound \
|
||||
--confirm '<confirmation>' --json
|
||||
```
|
||||
|
||||
After the State Hub rebind, make a fresh clone from the canonical URL. Do not
|
||||
trust an old-slug redirect as identity. Verify the Forge numeric ID and head,
|
||||
register the new path against the existing State Hub UUID, commit canonical
|
||||
source/frontmatter updates, and run `statehub fix-consistency` in the new clone.
|
||||
|
||||
The private source evidence file must include the assertions enforced by State
|
||||
Hub. Extra non-secret references are allowed:
|
||||
|
||||
```json
|
||||
{
|
||||
"fresh_clone": true,
|
||||
"forge_repository_id": 12345,
|
||||
"head_commit": "0123456789abcdef0123456789abcdef01234567",
|
||||
"clone_path": "<new-local-checkout>",
|
||||
"registration_evidence_ref": "<progress-event-or-file-reference>",
|
||||
"consistency_evidence_ref": "<progress-event-or-file-reference>"
|
||||
}
|
||||
```
|
||||
|
||||
```text
|
||||
statehub repo rename apply <operation-id> --phase source-synced \
|
||||
--evidence-file <private-mode-0600-source-evidence.json> \
|
||||
--confirm '<confirmation>' --json
|
||||
```
|
||||
|
||||
Collect evidence from every owning handoff. The checks file is a JSON object of
|
||||
named booleans; false or missing required checks block the phase:
|
||||
|
||||
```json
|
||||
{
|
||||
"old-and-new-slugs-one-uuid": true,
|
||||
"forge-id-and-head": true,
|
||||
"work-record-relationships": true,
|
||||
"telemetry-relationships": true,
|
||||
"external-handoffs-verified": true,
|
||||
"build-and-deployment-health": true
|
||||
}
|
||||
```
|
||||
|
||||
```text
|
||||
statehub repo rename verify <operation-id> --json
|
||||
statehub repo rename apply <operation-id> --phase consumers-verified \
|
||||
--checks-file <private-mode-0600-checks.json> \
|
||||
--evidence-file <private-mode-0600-consumer-evidence.json> \
|
||||
--confirm '<confirmation>' --json
|
||||
statehub repo rename apply <operation-id> --phase completed \
|
||||
--confirm '<confirmation>' --json
|
||||
```
|
||||
|
||||
## Read status without source code
|
||||
|
||||
At any time run:
|
||||
|
||||
```text
|
||||
statehub repo rename status <operation-id> --json
|
||||
```
|
||||
|
||||
Interpret the stable CLI envelope as follows:
|
||||
|
||||
| Field | Meaning |
|
||||
| --- | --- |
|
||||
| `state` | `planned` means resumable/incomplete, `achieved` means completed, `failed` means the last attempt failed, and `rolled-back` is terminal rollback. |
|
||||
| `phase` | Last durably achieved phase. An `error_code` does not advance it. |
|
||||
| `result.no_op` | The submitted phase was already achieved; operation identity was preserved. |
|
||||
| `next_safe_action.action` | Operator action permitted by the recorded phase. |
|
||||
| `next_safe_action.command` | Exact credential-free command skeleton for that action. |
|
||||
| `result.error_code` | Code from the last failed attempt; inspect it before retrying. |
|
||||
| `result.evidence.telemetry` | Phase duration, attempts, retries, failures, rollback, and verification outcome. |
|
||||
|
||||
The phase table is the recovery map:
|
||||
|
||||
| Achieved phase | What is true | Normal next command |
|
||||
| --- | --- | --- |
|
||||
| `preflighted` | Journal and immutable baseline exist; Forge may still use old name. | Apply `forge-renamed`. |
|
||||
| `forge-renamed` | Forge numeric ID is visible at the new name; State Hub may still be canonical on old slug. | Apply `statehub-rebound`. |
|
||||
| `statehub-rebound` | New slug is canonical and old slug is a protected alias on the same UUID. | Fresh clone/register, then apply `source-synced`. |
|
||||
| `source-synced` | Canonical clone and source projection are recorded. | Verify owned handoffs; apply `consumers-verified`. |
|
||||
| `consumers-verified` | Required checks and handoff evidence passed. | Re-run verify, then apply `completed`. |
|
||||
| `completed` | Rename is terminal; aliases/history remain. | Soak, residual handoff, then separately approved cleanup. |
|
||||
| `rollback-preflight` | Rollback safety and irreversible effects are recorded. | Review; use `rollback --execute` only if still safe. |
|
||||
| `rolled-back` | Old canonical coordinate is restored and the attempt remains auditable. | Verify consumers; a new attempt needs a new operation. |
|
||||
|
||||
The REST equivalents are repository-UUID addressed:
|
||||
|
||||
| CLI operation | REST operation |
|
||||
| --- | --- |
|
||||
| preflight | `POST /repos/{repo_id}/rename/preflight` |
|
||||
| start | `POST /repos/{repo_id}/rename/operations` |
|
||||
| status | `GET /repository-renames/operations/{operation_id}` |
|
||||
| apply phase | `POST /repos/{repo_id}/rename/operations/{operation_id}/phases/{phase}` |
|
||||
| verify | `GET /repos/{repo_id}/rename/operations/{operation_id}/verify` |
|
||||
| rollback preflight | `POST /repos/{repo_id}/rename/operations/{operation_id}/rollback-preflight` |
|
||||
| execute rollback | `POST /repos/{repo_id}/rename/operations/{operation_id}/rollback` |
|
||||
|
||||
Do not construct mutating REST requests when the CLI can express the operation;
|
||||
the CLI supplies confirmation, private-file, redaction, and next-action guards.
|
||||
|
||||
## Dashboard interpretation
|
||||
|
||||
The dashboard is a read surface, not the rename executor.
|
||||
|
||||
- Open `/repos/<old-slug>` after `statehub-rebound`. The amber alias banner must
|
||||
identify `<old-slug>` as an alias and link to `<new-slug>`.
|
||||
- Old and new routes must show the same repository UUID. The canonical page must
|
||||
list the protected alias.
|
||||
- Review repository dispatch, workplans/tasks, token totals, SBOM, services,
|
||||
capabilities, interface changes, inbox, and stale external-reference notices.
|
||||
- A stale Fabric/external projection is a visible handoff, not permission for
|
||||
State Hub to rewrite its source.
|
||||
- The dashboard does not currently render the phase journal. Use `statehub repo
|
||||
rename status` and `verify` as the authoritative operational views.
|
||||
- A healthy dashboard count is insufficient: final acceptance requires the
|
||||
relationship checksums in `verify`.
|
||||
|
||||
## Recovery playbook
|
||||
|
||||
Always reuse the same operation UUID. First run `status`; treat `phase` as the
|
||||
achieved state and the error as the failed attempt.
|
||||
|
||||
| Observation | Action |
|
||||
| --- | --- |
|
||||
| State Hub unavailable | Stop mutations. Restore central connectivity; then query the operation UUID. Rename phases are not edge-queueable. |
|
||||
| Preflight expired or evidence/head changed | Do not start. Resolve drift and issue a fresh preflight; keep or abandon the unused client operation UUID deliberately. |
|
||||
| Forge rename committed but journal remains `preflighted` | Retry `forge-renamed`; State Hub recognizes the expected numeric ID at the new coordinate and records a resumed phase. |
|
||||
| Forge old-slug lookup redirects to new slug | Treat the redirect as compatibility only. Verify numeric ID at the requested canonical coordinate; never use the redirect as identity evidence. |
|
||||
| Journal is `forge-renamed` | Prefer `statehub-rebound`; do not register a new State Hub repository. |
|
||||
| Journal is `statehub-rebound` but clone evidence is wrong | Keep both checkouts. Correct the fresh clone/remote/Forge-ID/head evidence and retry `source-synced`. |
|
||||
| Consumer check fails | Remain `source-synced` or `consumers-verified`; repair the named owner handoff or enter rollback preflight. Do not complete. |
|
||||
| Same phase submitted twice | A matching retry returns `no_op`. A changed operation/target/actor is a conflict, not a retry. |
|
||||
| Edge outbox contains old-slug writes | Pause preflight until replayed or explicitly resolved. Alias-aware central handlers preserve idempotency after rebind. |
|
||||
| Private Forge repository unreadable | Stop. Restore approved Forge access; never infer identity from a local checkout or redirect. |
|
||||
|
||||
## Rollback limits
|
||||
|
||||
Rollback is a separately confirmed two-step operation:
|
||||
|
||||
```text
|
||||
statehub repo rename rollback <operation-id> \
|
||||
--confirm 'rollback:<operation-id>' --json
|
||||
# Only after reviewing safe_to_rollback, blockers, and irreversible effects:
|
||||
statehub repo rename rollback <operation-id> \
|
||||
--confirm 'rollback:<operation-id>' --execute --json
|
||||
```
|
||||
|
||||
Rollback is unavailable when the old Forge slug is claimed, the expected Forge
|
||||
numeric ID/head is not observable, a competing operation exists, or State Hub
|
||||
routes are inconsistent. Never steal/delete a slug to make rollback appear
|
||||
safe.
|
||||
|
||||
The following are not automatically reversed:
|
||||
|
||||
- consumer commits, deployments, package/image publication, releases, or cache
|
||||
propagation;
|
||||
- external redirects and links already observed by users/automation;
|
||||
- credential-route, policy, DNS, namespace, or product/runtime changes;
|
||||
- fabric/SBOM/source projections owned by another repository;
|
||||
- the operation journal, lifecycle events, historical messages, aliases, or
|
||||
telemetry evidence.
|
||||
|
||||
After `source-synced`, every reversed external effect needs its own owner
|
||||
handoff and evidence. If an irreversible effect makes rollback unsafe, continue
|
||||
forward or stop for an explicit incident decision.
|
||||
|
||||
## Repository-boundary handoff format
|
||||
|
||||
Every external slug-bearing source is represented by both:
|
||||
|
||||
1. a live file-backed workplan/task or residual intake in the owning repository;
|
||||
2. a payload conforming to
|
||||
[`repository-rename-handoff-v1.schema.json`](schemas/repository-rename-handoff-v1.schema.json),
|
||||
attached to or referenced by that work record.
|
||||
|
||||
The example is
|
||||
[`repository-rename-handoff-v1.json`](examples/repository-rename-handoff-v1.json).
|
||||
The `handoff_id` is the live owning task/intake ID—not an informal label. The
|
||||
record names the source repository, old/new slug, affected paths or graph IDs,
|
||||
re-ingest procedure, verification checks, owning workplan/task, status, and
|
||||
non-secret evidence references.
|
||||
|
||||
Handoff rules:
|
||||
|
||||
- The target repository creates/routes the obligation but does not edit or
|
||||
close another repository's source task.
|
||||
- The owner acknowledges it in its own file-first workplan and synchronizes it
|
||||
to State Hub.
|
||||
- `verified` requires evidence from the owner. Equal counts, a message saying
|
||||
"done", or an uncommitted local edit are insufficient.
|
||||
- Evidence contains commit/check/report/receipt references and optional
|
||||
checksums only. Never include credentials, authorization headers, cookies,
|
||||
private preflight tokens, secret-bearing URLs, or secret values.
|
||||
- Unresolved handoffs become live residual records before the target workplan
|
||||
finishes. They are never parked only in this runbook, `SCOPE.md`, or prose.
|
||||
|
||||
## Cleanup is deliberately last
|
||||
|
||||
The old local checkout is the final removable asset because it is a recovery
|
||||
input, a comparison point, and evidence of the pre-cutover source. Removing it
|
||||
before terminal verification can strand the operator after an external rename,
|
||||
hide unpushed work, and destroy the easiest rollback comparison.
|
||||
|
||||
Only remove the old checkout after all of the following:
|
||||
|
||||
- operation is `completed` or intentionally `rolled-back`;
|
||||
- relationship verification passes;
|
||||
- canonical fresh clone is registered against the same State Hub UUID;
|
||||
- required owner handoffs are verified or represented as accepted live
|
||||
residuals;
|
||||
- the soak window covers deployments, automation, policies, packages, alerts,
|
||||
dashboards, and telemetry;
|
||||
- explicit cleanup approval identifies the exact old path and recovery source.
|
||||
|
||||
Record what was removed and whether recovery remains possible from Forgejo.
|
||||
The protected old slug alias is not cleanup material in this workflow; alias
|
||||
retirement requires a separate compatibility decision and operation.
|
||||
160
docs/schemas/repository-rename-handoff-v1.schema.json
Normal file
160
docs/schemas/repository-rename-handoff-v1.schema.json
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://state-hub.coulomb.social/schemas/repository-rename-handoff-v1.schema.json",
|
||||
"title": "State Hub repository rename handoff v1",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"schema_version",
|
||||
"handoff_id",
|
||||
"operation_id",
|
||||
"renamed_repository_id",
|
||||
"source_repository",
|
||||
"old_slug",
|
||||
"new_slug",
|
||||
"surface",
|
||||
"affected",
|
||||
"required_reingest",
|
||||
"verification",
|
||||
"owning_work_record",
|
||||
"status",
|
||||
"evidence",
|
||||
"sensitive_data_prohibited"
|
||||
],
|
||||
"properties": {
|
||||
"schema_version": {
|
||||
"const": "state-hub.repository-rename-handoff.v1"
|
||||
},
|
||||
"handoff_id": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "Canonical live task or intake record ID in the owning repository."
|
||||
},
|
||||
"operation_id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"renamed_repository_id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"source_repository": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-z0-9][a-z0-9-]*$",
|
||||
"description": "Repository that owns the slug-bearing source to change or re-ingest."
|
||||
},
|
||||
"old_slug": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-z0-9][a-z0-9-]*$"
|
||||
},
|
||||
"new_slug": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-z0-9][a-z0-9-]*$"
|
||||
},
|
||||
"surface": {
|
||||
"enum": [
|
||||
"fabric-projection",
|
||||
"ci",
|
||||
"package",
|
||||
"deployment",
|
||||
"credential-route",
|
||||
"policy",
|
||||
"sbom",
|
||||
"documentation",
|
||||
"consumer",
|
||||
"other"
|
||||
]
|
||||
},
|
||||
"affected": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["paths", "graph_ids"],
|
||||
"properties": {
|
||||
"paths": {
|
||||
"type": "array",
|
||||
"items": {"type": "string", "minLength": 1},
|
||||
"uniqueItems": true
|
||||
},
|
||||
"graph_ids": {
|
||||
"type": "array",
|
||||
"items": {"type": "string", "minLength": 1},
|
||||
"uniqueItems": true
|
||||
}
|
||||
},
|
||||
"anyOf": [
|
||||
{"properties": {"paths": {"minItems": 1}}},
|
||||
{"properties": {"graph_ids": {"minItems": 1}}}
|
||||
]
|
||||
},
|
||||
"required_reingest": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["required", "procedure"],
|
||||
"properties": {
|
||||
"required": {"type": "boolean"},
|
||||
"procedure": {"type": "string", "minLength": 1},
|
||||
"expected_source_revision": {"type": ["string", "null"]}
|
||||
}
|
||||
},
|
||||
"verification": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["check", "expected", "evidence_ref"],
|
||||
"properties": {
|
||||
"check": {"type": "string", "minLength": 1},
|
||||
"expected": {"type": "string", "minLength": 1},
|
||||
"evidence_ref": {"type": ["string", "null"]}
|
||||
}
|
||||
}
|
||||
},
|
||||
"owning_work_record": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["repository", "workplan_id", "task_id"],
|
||||
"properties": {
|
||||
"repository": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-z0-9][a-z0-9-]*$"
|
||||
},
|
||||
"workplan_id": {"type": "string", "minLength": 1},
|
||||
"task_id": {"type": "string", "minLength": 1}
|
||||
}
|
||||
},
|
||||
"status": {
|
||||
"enum": ["open", "acknowledged", "verified", "cancelled"]
|
||||
},
|
||||
"evidence": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["kind", "ref"],
|
||||
"properties": {
|
||||
"kind": {
|
||||
"enum": [
|
||||
"commit",
|
||||
"progress-event",
|
||||
"decision",
|
||||
"test-report",
|
||||
"deployment-observation",
|
||||
"reingest-receipt",
|
||||
"other"
|
||||
]
|
||||
},
|
||||
"ref": {"type": "string", "minLength": 1},
|
||||
"checksum": {
|
||||
"type": ["string", "null"],
|
||||
"pattern": "^[a-fA-F0-9]{64}$"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"sensitive_data_prohibited": {
|
||||
"const": true,
|
||||
"description": "Evidence contains references and checksums only, never credentials or secret values."
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue