Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,19 @@ Examples:
eligible enrolled agents, records the resulting task/proof ids, and uses the
core ledger for accounting.
- A provider plugin, such as product capture or edge compute, exposes a typed
`ProviderContract`; this plugin submits or waits on the resulting generic
workflow-compute task without embedding provider business logic.
`workflow-plugin-compute-core/protocol.ProviderContract`; this plugin submits
or waits on the resulting generic workflow-compute task without embedding
provider business logic.

`compute.provider` in this repository means "Workflow connection to a
wfcompute control plane." It is not a wfcompute worker/provider node. Provider
nodes, supervisors, package updates, proof verification, rewards, and dashboard
state belong to `workflow-compute`.

`compute.provider_catalog` consumes `workflow-compute/pkg/protocol.ProviderContract`
records. It intentionally does not define a separate plugin-local executor,
dependency, verification, reward, or network provider shape.
`compute.provider_catalog` consumes
`workflow-plugin-compute-core/protocol.ProviderContract` records. It
intentionally does not define a separate plugin-local executor, dependency,
verification, reward, or network provider shape.

Provider-specific contracts belong in the owning provider plugin. For example,
product capture owns product URL semantics and edge compute owns edge
Expand Down
12 changes: 6 additions & 6 deletions SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ C7: Standalone repo verification uses `GOWORK=off` unless parent `go.work` inclu
C8: `wfctl compute` CLI adapter owns operator UX only; scheduler/ledger/proof semantics stay core.
C9: External Workflow apps may use plugin outside wfcompute deployment/network if they can reach scoped control-plane client APIs.
C10: Public client control-plane access ≠ provider/admin mutation ingress.
C11: Plugin provider catalog details track `workflow-compute`'s typed `ProviderContract`, not a parallel plugin-local provider shape.
C11: Plugin provider catalog details track `workflow-plugin-compute-core/protocol.ProviderContract`, not a parallel plugin-local provider shape.
C12: Provider-specific typed steps belong in the owning provider plugin, not this generic compute adapter.
C13: Provider catalog entries are imported `workflow-compute` contracts; product/application assumptions belong in the calling workflow or provider plugin.
C13: Provider catalog entries are imported compute-core contracts; product/application assumptions belong in the calling workflow or provider plugin.
C14: Task residue policy submitted by this plugin is customer intent only; `workflow-compute` owns provider/product authority resolution, policy hashing, lease enforcement, and residue cleanup.

§I
Expand All @@ -29,7 +29,7 @@ repo: `workflow-plugin-compute` → Workflow external plugin adapter
core: `workflow-compute` → scheduler, worker, ledger, proof, reward, dashboard
module: `compute.provider` → control-plane connection + auth refs
module: `compute.pool` → org/pool/policy defaults
module: `compute.provider_catalog` → core `protocol.ProviderContract` declarations
module: `compute.provider_catalog` → public compute-core `protocol.ProviderContract` declarations
step: `step.compute_dispatch` → submit task
step: `step.compute_wait` → wait/read proof
step: `step.compute_map` → fanout deterministic task set
Expand All @@ -56,10 +56,10 @@ V15: `wfctl compute submit` supports command/container-build without leaking wor
V16: `wfctl compute accounting export` includes raw contribution units and policy reward outputs without leaking token
V17: docs/examples distinguish `compute.provider` Workflow connection from wfcompute provider/worker node
V18: plugin guidance for public control-plane use excludes bootstrap token, provider mutation, package/campaign/trust-root mutation, and raw agent/supervisor control APIs
V19: PR CI checks plugin provider catalog tests against current `GoCodeAlone/workflow-compute` main with a local module replace
V19: PR CI checks plugin provider catalog tests against public `workflow-plugin-compute-core/protocol.ProviderContract`
V20: manifest `stepTypes` exactly match runtime `StepTypes`
V21: plugin step/CLI surfaces must not mention product-capture, BMW, edge lambda, edge CDN, or another provider-specific business domain
V22: `compute.provider_catalog` accepts typed `protocol.ProviderContract` records from provider plugins without defining a parallel plugin-local provider schema
V22: `compute.provider_catalog` accepts typed `workflow-plugin-compute-core/protocol.ProviderContract` records from provider plugins without defining a parallel plugin-local provider schema
V23: `step.compute_dispatch` and `step.compute_map` accept valid short-lived task `residue_policy`, reject malformed residue policy locally, and do not compute policy hashes or override provider/product authority

§T
Expand All @@ -75,7 +75,7 @@ T7|x|add `wfctl compute github-runner` adapter commands for runner register/job
T8|x|add `wfctl compute submit command|container-build` for ad hoc workload demos|I.cmd,I.wfctl,C8,V10,V12,V15
T9|x|include rewards in `wfctl compute accounting export`|I.cmd,I.wfctl,C8,V10,V16
T10|x|document external Workflow client use cases and public client-surface boundary|C9,C10,V17,V18
T11|x|align provider catalog details with workflow-compute `ProviderContract` and gate drift in PR CI|C11,I.module,V19
T11|x|align provider catalog details with public compute-core `ProviderContract` and gate drift in PR CI|C11,I.module,V19
T12|x|remove provider-specific product-capture step/CLI/domain preview flattening from generic compute adapter|C12,I.step,V20,V21
T13|x|keep provider catalog validation generic so external provider plugins can supply edge/product contracts without plugin-local provider schema|C13,I.module,V19,V22
T14|x|submit optional short-lived task residue policy through dispatch/map steps without taking over core authority resolution|C14,I.step,V23
Expand Down
5 changes: 2 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ go 1.26.3
require (
github.com/GoCodeAlone/workflow v0.62.0
github.com/GoCodeAlone/workflow-compute v0.0.0-20260524063206-b3e8de8ce8d6
github.com/GoCodeAlone/workflow-plugin-compute-core v0.0.0-20260524082635-d967d825f9d3
)

require (
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
github.com/BurntSushi/toml v1.6.0 // indirect
github.com/DataDog/datadog-go/v5 v5.8.3 // indirect
github.com/GoCodeAlone/go-plugin v1.7.0 // indirect
Expand Down Expand Up @@ -40,7 +42,6 @@ require (
github.com/cloudevents/sdk-go/v2 v2.16.2 // indirect
github.com/containerd/errdefs v1.0.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/danieljoos/wincred v1.2.3 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/distribution/reference v0.6.0 // indirect
Expand Down Expand Up @@ -95,8 +96,6 @@ require (
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/sys/sequential v0.6.0 // indirect
github.com/moby/term v0.5.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
Expand Down
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ github.com/GoCodeAlone/workflow v0.62.0 h1:emFkTomDpVmBcEfw7quRO4V/J4qDsWNx/CrBd
github.com/GoCodeAlone/workflow v0.62.0/go.mod h1:659GGDrw3QJ7b625y9rf8QhKIpt1VCoEG0MxKu5tGQs=
github.com/GoCodeAlone/workflow-compute v0.0.0-20260524063206-b3e8de8ce8d6 h1:R2YBH5Vnkn/O1ksTRbzn5vaMN/GtnuFNiTDRF/FR0GY=
github.com/GoCodeAlone/workflow-compute v0.0.0-20260524063206-b3e8de8ce8d6/go.mod h1:T8yGXrRBm2USwkRFvMaoq4aPDt/f7JciZY9Y/l/upYs=
github.com/GoCodeAlone/workflow-plugin-compute-core v0.0.0-20260524082635-d967d825f9d3 h1:EPYnvSU3sZNnTbFyqZARKvHH00eUL5t7yWHLiBuKnOU=
github.com/GoCodeAlone/workflow-plugin-compute-core v0.0.0-20260524082635-d967d825f9d3/go.mod h1:1T6uCpUWPCNk6XPYgKq5CL/7LkD24MphKYsYVzF4jnI=
github.com/GoCodeAlone/yaegi v0.17.2 h1:WK6Y6e0t1a6U7r+S2dN3CGWW1PizYD3zO0zneToZPxM=
github.com/GoCodeAlone/yaegi v0.17.2/go.mod h1:z5Pr6Wse6QJcQvpgxTxzMAevFarH0N37TG88Y9dprx0=
github.com/IBM/sarama v1.47.0 h1:GcQFEd12+KzfPYeLgN69Fh7vLCtYRhVIx0rO4TZO318=
Expand Down Expand Up @@ -417,6 +419,7 @@ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
Expand Down
6 changes: 3 additions & 3 deletions internal/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"strings"
"time"

"github.com/GoCodeAlone/workflow-compute/pkg/protocol"
coreprotocol "github.com/GoCodeAlone/workflow-plugin-compute-core/protocol"
sdk "github.com/GoCodeAlone/workflow/plugin/external/sdk"
)

Expand Down Expand Up @@ -170,7 +170,7 @@ func poolModuleSchema() sdk.ModuleSchemaData {
}

type providerCatalogConfig struct {
Contracts []protocol.ProviderContract `json:"contracts"`
Contracts []coreprotocol.ProviderContract `json:"contracts"`
}

type providerCatalogModule struct {
Expand Down Expand Up @@ -226,7 +226,7 @@ func providerCatalogModuleSchema() sdk.ModuleSchemaData {
Category: "Compute",
Description: "Declarative workflow-compute provider contracts validated against the core provider catalog protocol.",
ConfigFields: []sdk.ConfigField{
{Name: "contracts", Type: "array", Description: "workflow-compute ProviderContract records.", Required: true},
{Name: "contracts", Type: "array", Description: "workflow-plugin-compute-core ProviderContract records.", Required: true},
},
}
}
60 changes: 30 additions & 30 deletions internal/module_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"strings"
"testing"

"github.com/GoCodeAlone/workflow-compute/pkg/protocol"
coreprotocol "github.com/GoCodeAlone/workflow-plugin-compute-core/protocol"
sdk "github.com/GoCodeAlone/workflow/plugin/external/sdk"
)

Expand Down Expand Up @@ -116,7 +116,7 @@ func TestModuleSchemas(t *testing.T) {
}
}

func TestProviderCatalogUsesWorkflowComputeProviderContracts(t *testing.T) {
func TestProviderCatalogUsesComputeCoreProviderContracts(t *testing.T) {
contract := validProviderContract()
raw := map[string]any{
"contracts": []any{toMap(t, contract)},
Expand All @@ -143,7 +143,7 @@ func TestProviderCatalogRejectsLegacyGroupedProviderDetails(t *testing.T) {
}
}

func TestProviderCatalogRejectsMalformedWorkflowComputeContract(t *testing.T) {
func TestProviderCatalogRejectsMalformedComputeCoreContract(t *testing.T) {
contract := validProviderContract()
contract.ConfigSchemaDigest = "sha256:not-hex"
_, err := newProviderCatalogModule("catalog", map[string]any{
Expand All @@ -157,9 +157,9 @@ func TestProviderCatalogRejectsMalformedWorkflowComputeContract(t *testing.T) {
func TestProviderCatalogAcceptsRuntimeProfileResiduePolicy(t *testing.T) {
contract := validProviderContract()
contract.RuntimeContract.Profiles[0].HostWorkspaceSupported = true
contract.RuntimeContract.Profiles[0].ResiduePolicy = protocol.ResiduePolicy{
Mode: protocol.ResidueModeProviderBound,
AllowedModes: []protocol.ResidueMode{protocol.ResidueModeIsolated, protocol.ResidueModeProviderBound},
contract.RuntimeContract.Profiles[0].ResiduePolicy = coreprotocol.ResiduePolicy{
Mode: coreprotocol.ResidueModeProviderBound,
AllowedModes: []coreprotocol.ResidueMode{coreprotocol.ResidueModeIsolated, coreprotocol.ResidueModeProviderBound},
MaxAgeSeconds: 600,
WipeOnFailure: true,
}
Expand All @@ -169,17 +169,17 @@ func TestProviderCatalogAcceptsRuntimeProfileResiduePolicy(t *testing.T) {
if err != nil {
t.Fatalf("newProviderCatalogModule: %v", err)
}
if module.config.Contracts[0].RuntimeContract.Profiles[0].ResiduePolicy.Mode != protocol.ResidueModeProviderBound {
if module.config.Contracts[0].RuntimeContract.Profiles[0].ResiduePolicy.Mode != coreprotocol.ResidueModeProviderBound {
t.Fatalf("residue policy not decoded: %+v", module.config.Contracts[0].RuntimeContract.Profiles[0].ResiduePolicy)
}
}

func TestProviderCatalogRejectsReusableResidueWithoutWorkspace(t *testing.T) {
contract := validProviderContract()
contract.RuntimeContract.Profiles[0].HostWorkspaceSupported = false
contract.RuntimeContract.Profiles[0].ResiduePolicy = protocol.ResiduePolicy{
Mode: protocol.ResidueModeProviderBound,
AllowedModes: []protocol.ResidueMode{protocol.ResidueModeProviderBound},
contract.RuntimeContract.Profiles[0].ResiduePolicy = coreprotocol.ResiduePolicy{
Mode: coreprotocol.ResidueModeProviderBound,
AllowedModes: []coreprotocol.ResidueMode{coreprotocol.ResidueModeProviderBound},
}
_, err := newProviderCatalogModule("catalog", map[string]any{
"contracts": []any{toMap(t, contract)},
Expand All @@ -189,9 +189,9 @@ func TestProviderCatalogRejectsReusableResidueWithoutWorkspace(t *testing.T) {
}
}

func validProviderContract() protocol.ProviderContract {
return protocol.ProviderContract{
ProtocolVersion: protocol.Version,
func validProviderContract() coreprotocol.ProviderContract {
return coreprotocol.ProviderContract{
ProtocolVersion: coreprotocol.Version,
ID: "workflow-compute-control-plane-v1",
PluginID: "workflow-plugin-compute",
ProviderID: "workflow-compute-control-plane",
Expand All @@ -200,29 +200,29 @@ func validProviderContract() protocol.ProviderContract {
DisplayName: "workflow-compute Control Plane",
ConfigSchemaRef: "schema://providers/workflow-plugin-compute/workflow-compute-control-plane/v1",
ConfigSchemaDigest: "sha256:" + strings.Repeat("b", 64),
OperatingModes: []protocol.NetworkOperatingMode{protocol.NetworkModeBatch},
WorkloadKinds: []string{string(protocol.WorkloadCommand), string(protocol.WorkloadContainerBuild)},
OperatingModes: []coreprotocol.NetworkOperatingMode{coreprotocol.NetworkModeBatch},
WorkloadKinds: []string{string(coreprotocol.WorkloadCommand), string(coreprotocol.WorkloadContainerBuild)},
ExecutorProviders: []string{"sandboxed-command"},
ExecutionSecurityTiers: []protocol.ExecutionSecurityTier{protocol.ExecutionSandboxedContainer},
ProofTiers: []protocol.ProofTier{protocol.ProofArtifactHash},
NetworkModes: []protocol.NetworkMode{protocol.NetworkModeRelay},
RuntimeContract: protocol.ProviderRuntimeContract{
Profiles: []protocol.ProviderRuntimeProfile{{
ExecutionSecurityTiers: []coreprotocol.ExecutionSecurityTier{coreprotocol.ExecutionSandboxedContainer},
ProofTiers: []coreprotocol.ProofTier{coreprotocol.ProofArtifactHash},
NetworkModes: []coreprotocol.NetworkMode{coreprotocol.NetworkModeRelay},
RuntimeContract: coreprotocol.ProviderRuntimeContract{
Profiles: []coreprotocol.ProviderRuntimeProfile{{
ID: "sandboxed-command-oci",
RuntimeProfile: protocol.RuntimeProfileSandboxedOCI,
RuntimeProfile: coreprotocol.RuntimeProfileSandboxedOCI,
ExecutorProvider: "sandboxed-command",
ExecutionSecurityTier: protocol.ExecutionSandboxedContainer,
ProofTier: protocol.ProofArtifactHash,
AllowedRuntimeTools: []protocol.ContainerRuntimeTool{protocol.ContainerRuntimePodman, protocol.ContainerRuntimeDocker, protocol.ContainerRuntimeNerdctl},
ExecutionSecurityTier: coreprotocol.ExecutionSandboxedContainer,
ProofTier: coreprotocol.ProofArtifactHash,
AllowedRuntimeTools: []coreprotocol.ContainerRuntimeTool{coreprotocol.ContainerRuntimePodman, coreprotocol.ContainerRuntimeDocker, coreprotocol.ContainerRuntimeNerdctl},
ImageDigestRequired: true,
RootFSDigestRequired: true,
AllowedMountRefs: []string{"workspace"},
WritableRootFS: protocol.RuntimePermissionForbidden,
Privileged: protocol.RuntimePermissionForbidden,
HostNamespaces: protocol.RuntimePermissionForbidden,
HostSocket: protocol.RuntimePermissionForbidden,
SeccompDisable: protocol.RuntimePermissionForbidden,
NoNewPrivilegesDisable: protocol.RuntimePermissionForbidden,
WritableRootFS: coreprotocol.RuntimePermissionForbidden,
Privileged: coreprotocol.RuntimePermissionForbidden,
HostNamespaces: coreprotocol.RuntimePermissionForbidden,
HostSocket: coreprotocol.RuntimePermissionForbidden,
SeccompDisable: coreprotocol.RuntimePermissionForbidden,
NoNewPrivilegesDisable: coreprotocol.RuntimePermissionForbidden,
ConformanceProfiles: []string{"sandboxed-oci-v1"},
}},
},
Expand Down
8 changes: 7 additions & 1 deletion plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,11 @@
"description": "Operate a workflow-compute control plane"
}
]
}
},
"dependencies": [
{
"name": "workflow-plugin-compute-core",
"constraint": ">=0.0.0"
}
]
}
Loading