diff --git a/docs/workstation-report-contract-family.md b/docs/workstation-report-contract-family.md new file mode 100644 index 0000000..6059d0d --- /dev/null +++ b/docs/workstation-report-contract-family.md @@ -0,0 +1,44 @@ +# Workstation Report Contract Family + +This note documents the first typed contract family for SourceOS workstation-v0 health and remediation reports. + +## Added schemas + +- `schemas/WorkstationDoctorReport.json` +- `schemas/WorkstationFixShellReport.json` +- `schemas/WorkstationFixFishReport.json` +- `schemas/WorkstationFixAllReport.json` + +## Added examples + +- `examples/workstationdoctorreport.json` +- `examples/workstationfixshellreport.json` +- `examples/workstationfixfishreport.json` +- `examples/workstationfixallreport.json` + +## Purpose + +These contracts promote the workstation doctor/fix surfaces from implementation-local JSON blobs into canonical typed reports. + +They are intended to support: +- local workstation health checks +- local remediation/audit flows +- evidence ingestion into higher-level control planes +- UI rendering in workspace/operator surfaces +- typed CLI and SDK generation downstream + +## Compatibility note + +The current Linux realization emits compatibility discriminator strings such as: +- `sourceos.doctor` +- `sourceos.fix.shell` +- `sourceos.fix.fish` +- `sourceos.fix.all` + +These schemas preserve those `kind` strings so the canonical layer stays aligned with the current implementation while still giving downstream systems a stable typed contract family. + +## Follow-on contract work + +1. Add optional metadata fields for host identity, generated timestamps, and artifact provenance if the local producer begins emitting them. +2. Add event/API exposure once the first agentplane and sociosphere consumers exist. +3. Consider a higher-order workstation bundle/envelope if multiple report artifacts need to be tied into one typed evidence object. diff --git a/examples/workstationdoctorreport.json b/examples/workstationdoctorreport.json new file mode 100644 index 0000000..b7b077f --- /dev/null +++ b/examples/workstationdoctorreport.json @@ -0,0 +1,33 @@ +{ + "kind": "sourceos.doctor", + "profile": "linux-dev/workstation-v0", + "ok": false, + "summary": { + "ok": 8, + "warn": 3, + "error": 1, + "info": 4 + }, + "results": [ + { + "level": "ok", + "name": "sourceos-binding", + "message": "profile bound" + }, + { + "level": "ok", + "name": "launcher", + "message": "present (fuzzel/wofi/rofi)" + }, + { + "level": "warn", + "name": "fusuma-service", + "message": "missing" + }, + { + "level": "error", + "name": "brew", + "message": "missing" + } + ] +} \ No newline at end of file diff --git a/examples/workstationfixallreport.json b/examples/workstationfixallreport.json new file mode 100644 index 0000000..929a2e2 --- /dev/null +++ b/examples/workstationfixallreport.json @@ -0,0 +1,39 @@ +{ + "kind": "sourceos.fix.all", + "mode": "apply", + "ok": true, + "results": { + "shell": { + "kind": "sourceos.fix.shell", + "mode": "apply", + "ok": true, + "summary": { + "patched": 2, + "would_patch": 0, + "reverted": 0, + "already_patched": 0, + "no_patch": 0, + "missing_file": 0 + }, + "results": [ + { + "file": "~/.bashrc", + "action": "patched" + }, + { + "file": "~/.zshrc", + "action": "patched" + } + ] + }, + "fish": { + "kind": "sourceos.fix.fish", + "mode": "apply", + "ok": true, + "result": { + "file": "~/.config/fish/config.fish", + "action": "patched" + } + } + } +} \ No newline at end of file diff --git a/examples/workstationfixfishreport.json b/examples/workstationfixfishreport.json new file mode 100644 index 0000000..9326d54 --- /dev/null +++ b/examples/workstationfixfishreport.json @@ -0,0 +1,9 @@ +{ + "kind": "sourceos.fix.fish", + "mode": "revert", + "ok": true, + "result": { + "file": "/home/user/.config/fish/config.fish", + "action": "reverted" + } +} \ No newline at end of file diff --git a/examples/workstationfixshellreport.json b/examples/workstationfixshellreport.json new file mode 100644 index 0000000..c16690f --- /dev/null +++ b/examples/workstationfixshellreport.json @@ -0,0 +1,23 @@ +{ + "kind": "sourceos.fix.shell", + "mode": "dry-run", + "ok": true, + "summary": { + "patched": 0, + "would_patch": 2, + "reverted": 0, + "already_patched": 0, + "no_patch": 0, + "missing_file": 0 + }, + "results": [ + { + "file": "/home/user/.bashrc", + "action": "would_patch" + }, + { + "file": "/home/user/.zshrc", + "action": "would_patch" + } + ] +} \ No newline at end of file diff --git a/schemas/WorkstationDoctorReport.json b/schemas/WorkstationDoctorReport.json new file mode 100644 index 0000000..e1bd70d --- /dev/null +++ b/schemas/WorkstationDoctorReport.json @@ -0,0 +1,64 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/WorkstationDoctorReport.json", + "title": "WorkstationDoctorReport", + "description": "Typed health-report envelope emitted by the SourceOS workstation doctor surface.", + "type": "object", + "additionalProperties": false, + "required": [ + "kind", + "profile", + "ok", + "summary", + "results" + ], + "properties": { + "kind": { + "const": "sourceos.doctor", + "description": "Compatibility discriminator emitted by the workstation doctor surface." + }, + "profile": { + "type": "string", + "minLength": 1, + "description": "Workstation profile identifier, such as linux-dev/workstation-v0." + }, + "ok": { + "type": "boolean", + "description": "Overall doctor outcome." + }, + "summary": { + "type": "object", + "additionalProperties": false, + "required": ["ok", "warn", "error", "info"], + "properties": { + "ok": { "type": "integer", "minimum": 0 }, + "warn": { "type": "integer", "minimum": 0 }, + "error": { "type": "integer", "minimum": 0 }, + "info": { "type": "integer", "minimum": 0 } + }, + "description": "Level counts across doctor checks." + }, + "results": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": ["level", "name", "message"], + "properties": { + "level": { + "type": "string", + "enum": ["ok", "warn", "error", "info"] + }, + "name": { + "type": "string", + "minLength": 1 + }, + "message": { + "type": "string" + } + } + }, + "description": "Per-check doctor results." + } + } +} \ No newline at end of file diff --git a/schemas/WorkstationFixAllReport.json b/schemas/WorkstationFixAllReport.json new file mode 100644 index 0000000..f61f810 --- /dev/null +++ b/schemas/WorkstationFixAllReport.json @@ -0,0 +1,36 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/WorkstationFixAllReport.json", + "title": "WorkstationFixAllReport", + "description": "Typed composite report envelope emitted by the SourceOS workstation fix-all surface.", + "type": "object", + "additionalProperties": false, + "required": [ + "kind", + "mode", + "ok", + "results" + ], + "properties": { + "kind": { + "const": "sourceos.fix.all", + "description": "Compatibility discriminator emitted by the fix-all surface." + }, + "mode": { + "type": "string", + "enum": ["apply", "dry-run", "revert"] + }, + "ok": { + "type": "boolean" + }, + "results": { + "type": "object", + "additionalProperties": false, + "required": ["shell", "fish"], + "properties": { + "shell": { "$ref": "WorkstationFixShellReport.json" }, + "fish": { "$ref": "WorkstationFixFishReport.json" } + } + } + } +} \ No newline at end of file diff --git a/schemas/WorkstationFixFishReport.json b/schemas/WorkstationFixFishReport.json new file mode 100644 index 0000000..60dafe9 --- /dev/null +++ b/schemas/WorkstationFixFishReport.json @@ -0,0 +1,39 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/WorkstationFixFishReport.json", + "title": "WorkstationFixFishReport", + "description": "Typed report envelope emitted by the SourceOS fish config fix helper.", + "type": "object", + "additionalProperties": false, + "required": [ + "kind", + "mode", + "ok", + "result" + ], + "properties": { + "kind": { + "const": "sourceos.fix.fish", + "description": "Compatibility discriminator emitted by the fish fix surface." + }, + "mode": { + "type": "string", + "enum": ["apply", "dry-run", "revert"] + }, + "ok": { + "type": "boolean" + }, + "result": { + "type": "object", + "additionalProperties": false, + "required": ["file", "action"], + "properties": { + "file": { "type": "string", "minLength": 1 }, + "action": { + "type": "string", + "enum": ["patched", "would_patch", "reverted", "already_patched", "no_patch", "missing_file"] + } + } + } + } +} \ No newline at end of file diff --git a/schemas/WorkstationFixShellReport.json b/schemas/WorkstationFixShellReport.json new file mode 100644 index 0000000..50d8839 --- /dev/null +++ b/schemas/WorkstationFixShellReport.json @@ -0,0 +1,56 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/WorkstationFixShellReport.json", + "title": "WorkstationFixShellReport", + "description": "Typed report envelope emitted by the SourceOS shell rc fix helper.", + "type": "object", + "additionalProperties": false, + "required": [ + "kind", + "mode", + "ok", + "summary", + "results" + ], + "properties": { + "kind": { + "const": "sourceos.fix.shell", + "description": "Compatibility discriminator emitted by the shell fix surface." + }, + "mode": { + "type": "string", + "enum": ["apply", "dry-run", "revert"] + }, + "ok": { + "type": "boolean" + }, + "summary": { + "type": "object", + "additionalProperties": false, + "required": ["patched", "would_patch", "reverted", "already_patched", "no_patch", "missing_file"], + "properties": { + "patched": { "type": "integer", "minimum": 0 }, + "would_patch": { "type": "integer", "minimum": 0 }, + "reverted": { "type": "integer", "minimum": 0 }, + "already_patched": { "type": "integer", "minimum": 0 }, + "no_patch": { "type": "integer", "minimum": 0 }, + "missing_file": { "type": "integer", "minimum": 0 } + } + }, + "results": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": ["file", "action"], + "properties": { + "file": { "type": "string", "minLength": 1 }, + "action": { + "type": "string", + "enum": ["patched", "would_patch", "reverted", "already_patched", "no_patch", "missing_file"] + } + } + } + } + } +} \ No newline at end of file