Skip to content

Commit 97c307f

Browse files
authored
Merge pull request #171 from AbdelStark/issue-141-adapter-author-workbench
Add adapter author workbench flow
2 parents da05aac + bfa0127 commit 97c307f

10 files changed

Lines changed: 647 additions & 32 deletions

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ releases may still include breaking changes when the public API needs to tighten
99

1010
### Added
1111

12+
- Added an adapter author workbench flow for provider promotion evidence. The non-Textual
13+
workbench now handles catalog providers, scaffold providers, and the direct-construction
14+
`jepa-wms` candidate; reports include runtime manifest status, fixture coverage, docs/catalog
15+
drift, redaction checks, promotion gaps by target status, safe artifact references, and validation
16+
commands, and `worldforge harness --flow workbench` exposes the same logic through TheWorldHarness.
1217
- Added cross-provider run comparisons for preserved eval and benchmark workspaces. `worldforge
1318
runs compare` now exports a shared JSON/Markdown/CSV model with provider rows, capability and
1419
operation context, fixture digest, suite version, budget status, event counts, missing evidence,

docs/src/provider-authoring-guide.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,19 @@ Before opening a provider PR, run the non-TUI workbench from a clean checkout:
4848
```bash
4949
uv run worldforge provider workbench mock
5050
uv run worldforge provider workbench <provider> --format json
51+
uv run worldforge provider workbench jepa-wms --format markdown
5152
uv run python scripts/generate_provider_docs.py --check
5253
```
5354

54-
The report lists the conformance helper required for every advertised capability, validates
55-
`tests/fixtures/providers/<provider>_*.json` playback files when they exist, links this guide, and
56-
prints a pasteable issue summary. It invokes only deterministic local providers by default. Use
57-
`--live` only on a prepared host when credentials, optional dependencies, injected runtimes, and
58-
runtime-owned artifacts are intentionally available.
55+
The report lists the conformance helper required for every advertised capability, planned
56+
capabilities for scaffold/candidate adapters, runtime manifest status, docs/catalog drift status,
57+
redaction checks, safe artifact references, and validation commands. It validates
58+
`tests/fixtures/providers/<provider>_*.json` playback files when they exist, including module-safe
59+
prefixes such as `jepa_wms_*.json` for direct-construction candidates. It also names missing
60+
promotion evidence by future status (`experimental`, `beta`, `stable`) so a scaffold gap is visible
61+
without turning into an accidental capability claim. It invokes only deterministic local providers
62+
by default. Use `--live` only on a prepared host when credentials, optional dependencies, injected
63+
runtimes, and runtime-owned artifacts are intentionally available.
5964

6065
## Adapter Decision Tree
6166

docs/src/roadmap-continuation.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -693,10 +693,10 @@ Out of scope:
693693

694694
Acceptance criteria:
695695

696-
- [ ] Workbench can run against `mock` and at least one scaffold/candidate in a clean checkout.
697-
- [ ] Output names missing evidence by promotion status.
698-
- [ ] Markdown output includes validation commands and safe artifact references.
699-
- [ ] TUI and CLI workbench views use the same non-Textual flow logic.
696+
- [x] Workbench can run against `mock` and at least one scaffold/candidate in a clean checkout.
697+
- [x] Output names missing evidence by promotion status.
698+
- [x] Markdown output includes validation commands and safe artifact references.
699+
- [x] TUI and CLI workbench views use the same non-Textual flow logic.
700700

701701
Validation:
702702

docs/src/theworldharness.md

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ The diagnostics, eval, and benchmark screens map directly to non-TUI commands:
9797
uv run worldforge doctor --registered-only
9898
uv run worldforge provider list
9999
uv run worldforge provider workbench mock
100+
uv run worldforge harness --flow workbench
100101
uv run worldforge benchmark --provider mock --iterations 2 --format json
101102
uv run worldforge eval --suite planning --provider mock --format json
102103
```
@@ -105,23 +106,32 @@ uv run worldforge eval --suite planning --provider mock --format json
105106

106107
`worldforge provider workbench <provider>` is the checkout-safe adapter author loop behind the
107108
harness provider development workflow. It does not import Textual and does not make live provider
108-
calls unless `--live` is passed explicitly. The default report is designed to paste into GitHub
109-
issues: provider profile, required capability conformance helpers, fixture JSON status, docs/catalog
110-
drift hints, redaction-safe provider event status, and exact follow-up commands.
109+
calls unless `--live` is passed explicitly. The same non-Textual report model powers the
110+
`worldforge harness --flow workbench` TUI path. The default report is designed to paste into GitHub
111+
issues or PR descriptions: provider profile, target source, required capability conformance helpers,
112+
planned capability surface, runtime manifest status, fixture JSON status, docs/catalog drift hints,
113+
redaction-safe provider event status, promotion evidence grouped by future status, safe artifact
114+
references, and exact validation commands.
111115

112116
```bash
113117
uv run worldforge provider workbench mock
118+
uv run worldforge provider workbench jepa-wms --format markdown
119+
uv run worldforge provider workbench genie --format json
114120
uv run worldforge provider workbench runway --format json
115121
uv run worldforge provider workbench runway --live
122+
uv run worldforge harness --flow workbench
116123
```
117124

118125
For deterministic local providers such as `mock`, the workbench invokes the advertised capability
119-
helpers. For HTTP adapters it validates matching `tests/fixtures/providers/<provider>_*.json`
120-
playback files and lists the capability helpers that the provider test module must cover. For
121-
host-owned local runtimes such as LeRobot and LeWorldModel, the default path inspects profile,
122-
health, docs, and fixtures while leaving injected-runtime/live smoke execution to prepared hosts.
123-
Run `uv run python scripts/generate_provider_docs.py --check` before opening a provider PR so
124-
profile metadata and generated catalog tables stay in sync.
126+
helpers. For scaffold or direct-construction candidates such as `genie` and `jepa-wms`, it names
127+
missing evidence by promotion status instead of implying the provider is ready. For HTTP adapters it
128+
validates matching `tests/fixtures/providers/<provider>_*.json` or Python module-safe fixture
129+
prefixes such as `jepa_wms_*.json`, and lists the capability helpers that the provider test module
130+
must cover. For host-owned local runtimes such as LeRobot and LeWorldModel, the default path
131+
inspects profile, health, docs, runtime manifests, and fixtures while leaving injected-runtime/live
132+
smoke execution to prepared hosts. Run
133+
`uv run python scripts/generate_provider_docs.py --check` before opening a provider PR so profile
134+
metadata and generated catalog tables stay in sync.
125135

126136
Completed checkout-safe flows also preserve a sanitized run workspace:
127137

src/worldforge/harness/flows.py

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,21 @@
6767
"mock provider benchmark matrix, and compare latency, throughput, and emitted events."
6868
),
6969
),
70+
HarnessFlow(
71+
id="workbench",
72+
title="Adapter Author Workbench",
73+
short_title="Workbench",
74+
focus="adapter authoring evidence",
75+
provider="Provider workbench",
76+
capability="authoring",
77+
command="uv run worldforge provider workbench mock",
78+
accent="#f0a35e",
79+
summary=(
80+
"Run the checkout-safe provider workbench against the stable mock provider and the "
81+
"direct-construction jepa-wms candidate, then collect promotion evidence, safe "
82+
"artifact references, and validation commands."
83+
),
84+
),
7085
)
7186

7287

@@ -126,6 +141,50 @@ def _run_diagnostics_demo(*, state_dir: Path, emit: bool = False) -> JSONDict:
126141
return summary
127142

128143

144+
def _run_workbench_demo(*, state_dir: Path, emit: bool = False) -> JSONDict:
145+
from worldforge.harness.workbench import (
146+
provider_workbench_markdown,
147+
provider_workbench_report,
148+
)
149+
150+
reports = [
151+
provider_workbench_report("mock", docs_root=Path.cwd()),
152+
provider_workbench_report("jepa-wms", docs_root=Path.cwd()),
153+
]
154+
providers = [str(report["provider"]) for report in reports]
155+
passed = sum(1 for report in reports if report.get("status") == "passed")
156+
safe_artifacts = [
157+
artifact
158+
for report in reports
159+
for artifact in report.get("safe_artifacts", [])
160+
if isinstance(artifact, dict)
161+
]
162+
validation_commands = sorted(
163+
{str(command) for report in reports for command in report.get("validation_commands", [])}
164+
)
165+
missing_by_provider = {
166+
str(report["provider"]): report["promotion"]["missing_evidence_by_status"]
167+
for report in reports
168+
}
169+
summary: JSONDict = {
170+
"demo_kind": "provider_workbench",
171+
"state_dir": str(state_dir),
172+
"providers": providers,
173+
"report_count": len(reports),
174+
"passed_count": passed,
175+
"failed_count": len(reports) - passed,
176+
"reports": reports,
177+
"safe_artifact_count": len(safe_artifacts),
178+
"safe_artifacts": safe_artifacts,
179+
"validation_commands": validation_commands,
180+
"missing_evidence_by_provider": missing_by_provider,
181+
"provider_events": [],
182+
}
183+
if emit:
184+
print("\n\n".join(provider_workbench_markdown(report) for report in reports))
185+
return summary
186+
187+
129188
# Demo modules import the optional-runtime provider classes at module scope, so
130189
# keep these imports lazy: loading the harness should not pull LeRobot/LeWorldModel
131190
# adapters into the base cold-start path.
@@ -145,6 +204,7 @@ def _run_lerobot_demo(**kwargs: object) -> JSONDict:
145204
"leworldmodel": _run_leworldmodel_demo,
146205
"lerobot": _run_lerobot_demo,
147206
"diagnostics": _run_diagnostics_demo,
207+
"workbench": _run_workbench_demo,
148208
}
149209

150210

@@ -806,6 +866,43 @@ def _steps_for(flow_id: str, summary: JSONDict) -> tuple[HarnessStep, ...]:
806866
"artifact=benchmark report json/markdown/csv",
807867
),
808868
)
869+
if flow_id == "workbench":
870+
candidate_missing = summary["missing_evidence_by_provider"]["jepa-wms"]
871+
return (
872+
HarnessStep(
873+
"Select authoring targets",
874+
"Use one stable catalog provider and one direct-construction candidate.",
875+
f"{', '.join(summary['providers'])} selected.",
876+
"providers=mock,jepa-wms",
877+
),
878+
HarnessStep(
879+
"Run checkout-safe workbench",
880+
"Invoke non-Textual provider_workbench_report without live provider calls.",
881+
f"{summary['passed_count']}/{summary['report_count']} reports passed.",
882+
"live=false",
883+
),
884+
HarnessStep(
885+
"Inspect promotion evidence",
886+
"Group missing evidence by target promotion status.",
887+
(
888+
"jepa-wms stable gaps: "
889+
f"{', '.join(candidate_missing.get('stable', [])) or 'none'}."
890+
),
891+
"promotion=experimental,beta,stable",
892+
),
893+
HarnessStep(
894+
"Check runtime and fixtures",
895+
"Read runtime manifest status and provider fixture coverage.",
896+
f"{summary['safe_artifact_count']} safe artifact references collected.",
897+
"fixtures=tests/fixtures/providers",
898+
),
899+
HarnessStep(
900+
"Render issue output",
901+
"Preserve validation commands and safe artifact references for PRs or issues.",
902+
f"{len(summary['validation_commands'])} validation commands listed.",
903+
"format=markdown,json",
904+
),
905+
)
809906
raise ValueError(f"unknown harness flow '{flow_id}'")
810907

811908

@@ -846,6 +943,36 @@ def _metrics_for(flow_id: str, summary: JSONDict) -> tuple[HarnessMetric, ...]:
846943
"provider events captured during benchmark samples",
847944
),
848945
)
946+
if flow_id == "workbench":
947+
candidate_missing = summary["missing_evidence_by_provider"]["jepa-wms"]
948+
stable_missing = candidate_missing.get("stable", [])
949+
return (
950+
HarnessMetric(
951+
"Targets",
952+
str(summary["report_count"]),
953+
", ".join(summary["providers"]),
954+
),
955+
HarnessMetric(
956+
"Passed",
957+
f"{summary['passed_count']}/{summary['report_count']}",
958+
"checkout-safe reports",
959+
),
960+
HarnessMetric(
961+
"Candidate gaps",
962+
str(len(stable_missing)),
963+
", ".join(stable_missing) or "none",
964+
),
965+
HarnessMetric(
966+
"Artifacts",
967+
str(summary["safe_artifact_count"]),
968+
"safe issue references",
969+
),
970+
HarnessMetric(
971+
"Commands",
972+
str(len(summary["validation_commands"])),
973+
"validation commands",
974+
),
975+
)
849976

850977
flow_label = "score" if flow_id == "leworldmodel" else "policy+score"
851978
return (
@@ -886,6 +1013,16 @@ def _transcript_for(flow_id: str, summary: JSONDict) -> tuple[str, ...]:
8861013
f"benchmark_event_count: {summary['benchmark_event_count']}",
8871014
f"commands: {' | '.join(summary['commands'])}",
8881015
)
1016+
if flow_id == "workbench":
1017+
candidate_missing = summary["missing_evidence_by_provider"]["jepa-wms"]
1018+
return (
1019+
"flow: workbench",
1020+
f"providers: {', '.join(summary['providers'])}",
1021+
f"passed: {summary['passed_count']}/{summary['report_count']}",
1022+
f"jepa-wms_missing_stable: {', '.join(candidate_missing.get('stable', [])) or 'none'}",
1023+
f"safe_artifacts: {summary['safe_artifact_count']}",
1024+
f"validation_commands: {' | '.join(summary['validation_commands'])}",
1025+
)
8891026

8901027
lines = [
8911028
f"flow: {flow_id}",

0 commit comments

Comments
 (0)