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
17 changes: 15 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Changelog

## 0.1.0 — stable

- Promote the accepted three-operation component without runtime, WIT or
dependency changes; the stable manifest produces a new package identity.
- The official locked 0.1.0-rc.1 passed CAPI caller-replacement acceptance on
2026-09-10: five profiles, ten scenarios, 319 unchanged assertions and both
exact expected-RED fingerprints. This is evidence for the RC; stable
publication and its exact artifact verification remain separate gates.
- Document the fixed Start identity, internal RPC aliases, per-filter History
flags and timeout ceilings, and empty-cache acquisition with an existing lock.
- Requires Sigil >=0.35.0, <0.36.0 and Host API 1.3; no compatibility claim for
Sigil 0.34.x or 0.36.x.

## 0.1.0-rc.1 — release candidate

- Bounded WebAssembly Temporal WorkflowService client for Start, Describe and
Expand All @@ -11,5 +24,5 @@
- Main-only immutable keyless-provenance release pipeline, separate from
explicitly non-gating local development packages.

This is not a claim of real CAPI caller replacement acceptance. That acceptance
must use the official locked RC and precedes stable Temporal promotion.
At RC publication, real CAPI caller replacement acceptance remained open. The
subsequent accepted run is recorded above; it used the ordinary official lock.
71 changes: 64 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
# Sigil Temporal plugin

Release candidate for the measured three-operation `wasm.temporal` component:
The measured three-operation `wasm.temporal` component:
start, describe and caller-paginated history.

The candidate is **0.1.0-rc.1**, requiring stable **Sigil 0.35.x** and Host API
Version **0.1.0** requires stable **Sigil 0.35.x** and Host API
1.3/schema 4. A version in this checkout is not evidence that its GitHub release
exists. CAPI's real caller replacement acceptance remains open; an official RC
enables that gate through normal project execution. Routing, authority, TLS policy, credentials and transport limits belong
exists. The official locked **0.1.0-rc.1** passed CAPI caller-replacement
acceptance on **2026-09-10**: five profiles, ten scenarios, 319 unchanged
assertions and both exact expected-RED fingerprints. Stable promotion preserves
the component bytes but creates a new manifest/package identity requiring its
own reviewed publication and verification. Routing, authority, TLS policy,
credentials and transport limits belong
to the operator-frozen Sigil host profile. The component receives none of them.
It performs no retries, redirects, reconnections, sleeps or implicit pagination.

Expand Down Expand Up @@ -49,6 +53,51 @@ compatibility, Sigil's scenario-level sticky-fault behavior, or CAPI acceptance.
The optional project-side polling helper and its caller obligations are in
[`examples/README.md`](examples/README.md). It is not an additional WIT export.

## Operator and caller contract

The Lua export names are `start-workflow-execution`,
`describe-workflow-execution`, and `get-workflow-execution-history`. The host
profile's RPC keys are a **different namespace**: the plugin sends exactly
`start`, `describe`, and `history`. Within an existing profile named `example`,
use these entries (this is a fragment, not a complete operator configuration):

```toml
[plugins.grants.temporal.grpc.example.rpcs]
start = { path = "/temporal.api.workflowservice.v1.WorkflowService/StartWorkflowExecution", kind = "mutation" }
describe = { path = "/temporal.api.workflowservice.v1.WorkflowService/DescribeWorkflowExecution", kind = "read" }
history = { path = "/temporal.api.workflowservice.v1.WorkflowService/GetWorkflowExecutionHistory", kind = "read" }
```

The existing profile's `request_policy` must use
`identity = "sigil-temporal@0.1.0"`. This is the plugin's fixed protobuf Start
identity, including for RC packages, not an operator-chosen client name or the
host-owned `client-version` metadata. Keep namespace, workflow-id prefix,
workflow type and task queue confined to the intended caller. The scenario's
`profile` must name that same configured profile.

Keep the network endpoint referenced by the gRPC profile: it supplies the
host-owned route, **not raw network authority for the guest**. Sigil 0.35.0 may
warn that this network grant is irrelevant even though the gRPC route is
retained. Do not remove the route or add raw `network`/`secrets` capability to
silence that warning; those capabilities cannot coexist with semantic
`grpc-unary`. Authorize only the official source for `grpc-unary`, without
widening installation or third-party policy.

History accepts exactly these request shapes; each call returns one page:

| `filter` | `wait-new-event` | `skip-archival` | Maximum `timeout-millis` |
| --- | --- | --- | --- |
| `close-event` | `true` | `true` | 65000 |
| `all-events` | `false` | `false` | 10000 |

Start and Describe also cap `timeout-millis` at 10000. Timeouts must be positive;
the host's operator, scenario and outer-call deadlines can shorten them further.
A 10000 ms timeout is admissible for all operations, but is not a guarantee of
that much execution time. Close-event history long-polls; reading a still-running
workflow may reach the deadline. Follow nonempty page tokens explicitly, keep
Start single-shot with one caller-owned request ID, and propagate infrastructure
errors rather than converting them into expected product failures.

## Local packaging (non-gating)

`plugin.local.toml` is an explicit **local development manifest**, not release
Expand Down Expand Up @@ -135,14 +184,22 @@ without altering protobuf payloads or the interface contract.
does not rebuild. It verifies a draft readback, emits keyless GitHub OIDC
provenance and checks the immutable public release and its asset hashes.
Existing versions are burned rather than overwritten or republished.
5. Install the exact official RC from a fresh cache, then add and sync it:
5. Acquire the exact published version and verify its official lock. For an
existing project lock with an empty cache, sync that lock **before** add:

```sh
sigil plugin install temporal@0.1.0-rc.1
sigil plugin add temporal@0.1.0-rc.1
sigil plugin sync
sigil plugin install temporal@0.1.0
sigil plugin add temporal@0.1.0
sigil plugin sync
```

These commands require the stable release to exist. During RC acceptance,
use the exact approved RC version instead. Omit the first sync when there
is no existing lock; omit add when the lock already selects the intended
version. Add resolves the whole project lock, so first populate dependencies
already pinned there rather than assuming an empty cache contains them.

Sigil 0.35.0's `add` grants project access and can acquire a missing package
through the verified remote-install path. Explicit install-first is
recommended here to expose acquisition evidence separately and keep the
Expand Down
13 changes: 13 additions & 0 deletions RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ publication job or erase a draft/tag/attestation to reuse the identity.

The public RC must be discoverable by exact version, installed from an empty
cache with official-github-provenance-v1, then added to a project lock and synced.
When the project already has a lock, sync it first to populate its existing
dependencies before adding the intended version. Add resolves the whole lock;
omit add if it already selects that version. Apply the same acquisition order
when verifying the stable package, without substituting its RC package identity.
Explicit install-first separates acquisition evidence for auditing and retains
compatibility with older hosts; it is not a limitation of Sigil 0.35.0, whose
`plugin add` can acquire a missing package through verified remote installation.
Expand All @@ -65,3 +69,12 @@ expected-RED fingerprints with pinned service/rig identities. No non-gating
After acceptance, stable 0.1.0 is a new independently reviewed candidate and
publication. Promotion does not mutate the immutable prerelease or claim its
package digest is unchanged when the manifest version changes.

The official locked 0.1.0-rc.1 received CAPI caller-replacement acceptance on
2026-09-10 (five profiles, ten scenarios, 319 unchanged assertions, both exact
expected-RED fingerprints). This closes the RC service-acceptance prerequisite,
not the stable exact-candidate review or publication gate. Stable preparation
must reproduce the accepted component BLAKE3
`b25139ed2e6eeab88ed26f8e306621cd83869670084f986e481143b57acc372d`;
retain the new package/manifest identities separately. The operator/caller
requirements that enabled acceptance are documented in the README.
4 changes: 2 additions & 2 deletions plugin.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Official release candidate; CAPI acceptance remains a separate gate.
# Stable release manifest; publication remains an independently reviewed gate.
schema_version = 4
name = "temporal"
version = "0.1.0-rc.1"
version = "0.1.0"
description = "Bounded Temporal WorkflowService client"
license = "MIT"

Expand Down
7 changes: 4 additions & 3 deletions tests/test_release_pack.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@
class ReleaseContractTests(unittest.TestCase):
def test_release_manifest_keeps_local_and_official_versions_separate(self):
data = (ROOT / "plugin.toml").read_bytes()
self.assertEqual(release.validate_manifest(data)["version"], "0.1.0-rc.1")
release.validate_manifest(data.replace(b"0.1.0-rc.1", b"0.1.0"))
self.assertEqual(release.validate_manifest(data)["version"], "0.1.0")
version_line = b'version = "0.1.0"'
release.validate_manifest(data.replace(version_line, b'version = "0.1.0-rc.1"'))
for version in (b"0.1.0-dev.1", b"0.1.0-rc.0", b"0.1.0-rc.01", b"0.1.0+build", b"0.2.0"):
with self.subTest(version=version), self.assertRaises(ValueError):
release.validate_manifest(data.replace(b"0.1.0-rc.1", version))
release.validate_manifest(data.replace(version_line, b'version = "' + version + b'"'))
with self.assertRaises(ValueError):
release.validate_manifest((ROOT / "plugin.local.toml").read_bytes())
with self.assertRaises(ValueError):
Expand Down