Complete extension SDK maturity

This commit is contained in:
2026-05-15 15:34:55 +02:00
parent 67f2fc5346
commit 6758b3992c
19 changed files with 680 additions and 14 deletions

View File

@@ -65,6 +65,8 @@ when a wrapper script or container entrypoint should keep commands shorter.
For the repeatable external extension acceptance path, including validation,
planning, live execution, and retained result review, see
`docs/EXTERNAL-EXTENSION-ACCEPTANCE.md`.
For extension-author contracts such as profile schema descriptors and
normalizer plug-ins, see `docs/EXTENSION-SDK.md`.
## CLI Results

View File

@@ -75,6 +75,8 @@ The key runtime fields are:
- `check_groups`: named groups that assessment profiles can select.
- `preflight_runner`: optional runner ID used before selected check groups.
- `runner_entrypoints`: concrete runner declarations.
- `normalizers`: optional plug-ins that convert native runner output into the
stable runner-result shape before evidence is written.
- `mappings`: mapping set IDs under `mappings/<mapping-id>.json`.
- `certification_boundary`: explicit statement of what the extension does not
certify.
@@ -283,6 +285,71 @@ or `infrastructure_error`, downstream check groups for that extension are not
executed; they receive `blocked` evidence with `blocked_reason:
preflight_failed`.
## Normalizer Plug-ins
Runners can keep returning guide-board-ready result objects directly. When a
runner wraps a native harness or scanner that writes its own result format, the
extension can add a normalizer descriptor:
```json
{
"id": "native-probe-normalizer",
"kind": "python_module",
"module_path": "normalizers/native_probe.py",
"callable": "normalize",
"runner_ref": "native-probe",
"description": "Converts native runner output into guide-board evidence."
}
```
Normalizers are declared in `extension.json` under `normalizers`. The original
string shorthand remains valid for descriptive-only entries, but only descriptor
objects are loaded and invoked by the core.
The first supported normalizer kind is `python_module`. Its module path is
resolved relative to the extension root and must stay inside that root. The
callable receives one context object:
- `root`: guide-board core root path as a string.
- `extension_path`: extension root path as a string.
- `run_dir`: output run directory path as a string.
- `run_id`: current run ID.
- `plan`: full run plan snapshot.
- `step`: the step being normalized.
- `target_profile`: target profile snapshot.
- `assessment_profile`: assessment profile snapshot.
- `normalizer`: manifest normalizer descriptor.
- `runner_result`: the current runner-result object.
A normalizer returns any subset of the runner-result fields:
```python
def normalize(context: dict) -> dict:
return {
"result": "pass",
"observations": ["Native result was normalized."],
"facts": {"native_status": "ok"},
"artifact_refs": ["artifacts/native-result.json"],
"requirement_refs": ["framework.requirement"],
}
```
The core merges the normalizer output over the runner result:
- `result` replaces the previous result.
- `observations` are appended.
- `facts` are merged.
- `artifact_refs` and `requirement_refs` are deduplicated.
- `normalizer_refs` is recorded in evidence facts when any normalizer runs.
If a normalizer raises an exception, the step becomes
`infrastructure_error` evidence and the run still produces its normal artifact
set.
The bundled `extensions/sdk-fixture` extension is the copyable reference path
for profile schemas, a native-output runner, a normalizer, mappings, and fixture
profiles.
## Result Statuses
Initial statuses:
@@ -303,11 +370,14 @@ Initial statuses:
## Current Extension Examples
- `sample-noop`: no runner, used to validate the core contracts.
- `sdk-fixture`: compact SDK fixture covering profile schemas, runner output,
normalizer invocation, mapping, and fixture profiles.
- `open-cmis-tck`: provides a Python CMIS Browser Binding preflight runner and
declares the future external OpenCMIS TCK runner.
## Next SDK Steps
- Add normalizer plug-in contracts.
- Add extension-owned schema validation for domain-specific target profile
fields.
- Broaden normalizer examples as real external extensions adopt native harness
result formats.
- Add more extension-owned schema validation examples for assessment-specific
domain constraints.

View File

@@ -15,6 +15,9 @@ domain-specific harness logic into the core.
runtime dependencies, and harness behavior remain owned by that extension
repository.
For a dependency-light SDK reference extension that can be copied into a
temporary external repository, see `extensions/sdk-fixture`.
## Acceptance Stages
Run these stages from the guide-board repository.

View File

@@ -93,7 +93,22 @@
}
}
},
"normalizers": { "type": "array", "items": { "type": "string" } },
"normalizers": {
"type": "array",
"items": {
"type": ["string", "object"],
"additionalProperties": false,
"required": ["id", "kind", "module_path", "callable"],
"properties": {
"id": { "type": "string" },
"kind": { "type": "string", "enum": ["python_module"] },
"module_path": { "type": "string" },
"callable": { "type": "string" },
"runner_ref": { "type": ["string", "null"] },
"description": { "type": ["string", "null"] }
}
}
},
"mappings": { "type": "array", "items": { "type": "string" } },
"report_fragments": { "type": "array", "items": { "type": "string" } },
"dependencies": { "type": "array", "items": { "type": "string" } },