feature request batch from codex convo #508

Closed
opened 2026-07-02 04:19:01 +00:00 by coilysiren · 3 comments
Owner

The problem

I did a design session with codex web, its outputs are below

Proposed change

Reframe Ward as a governed coding-agent execution layer and finish the driver/workflow/provider seams

Summary

Ward has outgrown the external category of “harness driver.”

That term is still accurate internally: Ward drives agent harnesses/CLIs into constrained execution contexts. But externally, it undersells the product boundary. Ward is not primarily an eval harness, benchmark runner, or toy session manager. It is a governed execution layer for realtime AI-assisted engineering work.

This parent issue tracks the accepted gaps from the architecture review:

  1. Rename/reframe the external category.
  2. Finish manifest-backed agent adapter lookup.
  3. Add workflow modes.
  4. Continue abstracting Forgejo as a provider boundary.

Explicitly out of scope for this parent:

  • velocity metrics
  • model-proxy integration
  • read-only credential hardening

Those are intentionally deferred/denied for now.

Current framing problem

The README currently leads with:

ward is a harness driver.

That is precise but too narrow.

The stronger external claim is closer to:

Ward is a guarded coding-agent execution layer.

or:

Ward turns subscription-authenticated coding CLIs into contained, auditable engineering workers.

or:

Ward launches existing coding agents into governed engineering workflows with repo-scoped credentials, policy gates, and durable run artifacts.

“Harness driver” can remain an internal implementation term, but it should not be the first thing a new reader sees.

Desired product framing

Ward should present itself as the runtime/control layer above coding agents:

Human / Director
  → Ward
  → contained agent worker
  → repo / issue / workflow system

Ward owns:

  • launch context
  • containment
  • agent-driver selection
  • issue/work-item lifecycle
  • repo access
  • policy/audit integration
  • workflow progression
  • outcome reconciliation

The agent owns:

  • code reasoning
  • implementation
  • local tool use inside the container
  • commit/merge/push behavior within the granted workflow

The key positioning distinction:

Not: “Ward tests agents.”
Yes: “Ward drives agents through real engineering work safely enough to use live.”

Scope

1. Rename the external category

Update README/docs language so Ward is not primarily described as a “harness driver.”

Proposed external category:

guarded coding-agent execution layer

Possible README opener:

# ward

Ward is a guarded execution layer for coding agents.

It launches subscription-authenticated agent CLIs into ephemeral, least-access
containers; drives them through issue-to-merge workflows; and records the work
behind cli-guard policy, audit, and repo-scoped credentials.

Internally, Ward is a manifest-backed harness driver: it knows how to launch
Claude Code, Codex, OpenCode, Goose, and future coding agents through their
own CLI dialects.

The term harness driver should remain valid in lower-level docs where the adapter/launcher implementation is discussed.

Acceptance criteria

  • README first sentence no longer says only “ward is a harness driver.”

  • README explains Ward as a guarded execution layer for coding agents.

  • “Harness driver” is preserved as an internal architecture term.

  • Docs consistently distinguish:

    • external product category
    • internal driver implementation
    • underlying cli-guard policy/audit engine

2. Finish manifest-backed adapter lookup

Ward already has the right direction: the fleet manifest should be the single source of per-agent divergence.

The goal is to remove remaining hardcoded driver switches and make the launcher consume the manifest/registry consistently.

Today the fleet records:

  • agent name
  • binary
  • context level
  • stream mode
  • auth mode
  • argv dialects
  • model/endpoint metadata for some agents

The desired state is:

fleet manifest
  → parsed agent registry
  → launcher projection
  → container env
  → preflight/headless/interactive argv

No launch-path behavior should require hardcoded switch mode { claude, codex, opencode, goose } logic unless it is explicitly transitional and pinned by tests.

Expand the adapter model

Current manifest fields are launch-shape oriented. Add capability-shape fields where useful:

capabilities:
  preflight: true | false
  headless: true | false
  interactive: true | false
  stream: stream-json | stdout | none
  resume: true | false
  supports_images: true | false
  supports_mcp: inherited | native | none
  auth_source: host | container | none

Exact schema can differ, but the distinction should be clear:

  • argv describes how to invoke the agent.
  • capabilities describes what Ward may expect from that agent.

Acceptance criteria

  • Remaining driver-specific switches in launch/compute paths are eliminated or isolated behind a manifest-backed registry.
  • agentBinary, contextLevel, hostPreflightArgv, stream handling, and auth shape derive from the fleet/adapter registry.
  • Tests pin current Claude/Codex/OpenCode/Goose behavior before and after migration.
  • Adding a new driver should require manifest/config changes and tests, not scattered Go switch edits.
  • Error messages name the manifest/registry source when an agent is malformed or unsupported.

3. Add workflow modes

Ward currently centers the fast path:

issue → contained engineer → commit → merge to main → push → close issue

That is valid for personal/high-trust repos, but it should not be the only conceptual workflow. Teams will expect different landing policies.

Add explicit workflow modes.

Candidate modes:

direct-main
pr
patch-only

direct-main

Current behavior.

The agent may carry the issue through commit, merge to main, push, and close.

Intended for:

  • solo repos
  • trusted automation repos
  • fast internal loops
  • low-review surfaces

pr

The agent carries the work to a branch/PR instead of landing directly.

Expected lifecycle:

issue → branch → commit → push branch → open PR → report PR

Follow-up loops may handle:

  • CI failure
  • review comments
  • requested changes
  • merge after approval

This can start minimal. The first slice does not need to solve all review automation.

patch-only

The agent produces a patch/diff/artifact but receives no push authority.

Expected lifecycle:

issue → contained run → patch artifact → comment/report

Useful for:

  • external repos
  • untrusted targets
  • experiments
  • high-risk work
  • future provider abstraction

Interface sketch

Possible CLI surface:

warded engineer #98 --workflow direct-main
warded engineer #98 --workflow pr
warded engineer #98 --workflow patch-only

Possible config default:

agent:
  workflow: direct-main

or:

workflows:
  default: direct-main

Acceptance criteria

  • Workflow mode is explicit in plan/print output.
  • Workflow mode is visible in container labels/env or run metadata.
  • Seed prompt/done condition changes based on workflow.
  • direct-main preserves existing behavior.
  • pr does not instruct the agent to merge directly to main.
  • patch-only does not grant push authority or instruct the agent to push.
  • Docs explain which workflow mode is appropriate for which trust level.

4. Continue abstracting Forgejo as a provider boundary

Forgejo-first is correct for the current fleet, but Forgejo should not define Ward’s architecture.

Ward needs a provider boundary around work items and source control operations.

The current system is issue/Forgjo-shaped:

  • parse issue refs
  • read issue title/body/comments
  • reserve with comments
  • post outcomes
  • close issue
  • list repo/org backlog
  • expand org scope
  • clone/push against Forgejo remotes

That should be abstracted behind provider concepts.

Work item provider

Sketch:

type WorkItemProvider interface {
    ParseRef(raw string) (WorkRef, error)
    Read(ctx context.Context, ref WorkRef) (WorkItem, error)
    ReadThread(ctx context.Context, ref WorkRef) ([]Comment, error)
    Reserve(ctx context.Context, ref WorkRef, run RunRef) error
    Release(ctx context.Context, ref WorkRef, run RunRef) error
    Comment(ctx context.Context, ref WorkRef, body string) error
    Close(ctx context.Context, ref WorkRef, resolution CloseResolution) error
}

SCM provider

Sketch:

type SCMProvider interface {
    CloneURL(repo RepoRef) string
    PushURL(repo RepoRef) string
    OpenPR(ctx context.Context, req PullRequestRequest) (PullRequestRef, error)
    ReadCI(ctx context.Context, ref ChangeRef) (CIStatus, error)
    Merge(ctx context.Context, ref ChangeRef, strategy MergeStrategy) error
}

Exact interfaces should evolve from current code rather than be imposed wholesale. The important boundary is:

Ward workflow engine
  → provider interface
  → Forgejo implementation

not:

Ward workflow engine
  → Forgejo everywhere

Acceptance criteria

  • Forgejo-specific parsing/commenting/listing behavior is progressively isolated behind provider-shaped functions or interfaces.
  • Existing Forgejo behavior remains unchanged.
  • New workflow-mode work does not deepen Forgejo coupling.
  • Public docs refer to “work items” or “issues” where generic, and “Forgejo issues” only where implementation-specific.
  • Future GitHub/GitLab support is architecturally plausible without rewriting the driver.

Explicit non-goals

Velocity metrics

Do not include velocity instrumentation in this issue.

Potential future metrics such as time-to-land, human intervention count, redispatch count, blocked rate, salvage rate, and wall-clock-to-land are intentionally out of scope.

Model-proxy integration

Do not add model-proxy integration here.

Ward should remain focused on the top driver layer for this parent issue.

Read-only credential hardening

Do not prioritize dispatch-only credentials or deeper read-only credential isolation in this issue.

Known soft edges may remain documented, but this parent does not track fixing them.

Suggested breakout issues

  • Reword README and top-level docs around “guarded coding-agent execution layer.”
  • Replace remaining driver switches with manifest-backed adapter lookup.
  • Add agent capability fields to the fleet manifest.
  • Add --workflow direct-main|pr|patch-only.
  • Implement workflow-specific seed prompts and done conditions.
  • Implement patch-only as the first non-direct workflow.
  • Implement pr as branch + PR creation, without review-loop automation.
  • Extract Forgejo work-item operations behind a provider boundary.
  • Extract SCM operations behind a provider boundary.
  • Update docs to distinguish product category, driver internals, workflows, and providers.

Done when

Ward’s public story reads as:

Ward is a guarded execution layer for coding agents.

and the implementation supports that story by having:

  • manifest-backed agent driver selection,
  • explicit workflow modes,
  • and a Forgejo implementation behind a provider seam.

At that point, “harness driver” remains true, but it is no longer the category Ward is trying to win.

Alternatives considered

No response

Before filing

  • I searched existing issues and this is not a duplicate.
  • This stays within ward's scope (the dev-verb gate / agent driver), not a personal-infra or downstream-repo verb.
### The problem I did a design session with codex web, its outputs are below ### Proposed change # Reframe Ward as a governed coding-agent execution layer and finish the driver/workflow/provider seams ## Summary Ward has outgrown the external category of “harness driver.” That term is still accurate internally: Ward drives agent harnesses/CLIs into constrained execution contexts. But externally, it undersells the product boundary. Ward is not primarily an eval harness, benchmark runner, or toy session manager. It is a governed execution layer for realtime AI-assisted engineering work. This parent issue tracks the accepted gaps from the architecture review: 1. Rename/reframe the external category. 2. Finish manifest-backed agent adapter lookup. 3. Add workflow modes. 4. Continue abstracting Forgejo as a provider boundary. Explicitly out of scope for this parent: * velocity metrics * model-proxy integration * read-only credential hardening Those are intentionally deferred/denied for now. ## Current framing problem The README currently leads with: > ward is a harness driver. That is precise but too narrow. The stronger external claim is closer to: > Ward is a guarded coding-agent execution layer. or: > Ward turns subscription-authenticated coding CLIs into contained, auditable engineering workers. or: > Ward launches existing coding agents into governed engineering workflows with repo-scoped credentials, policy gates, and durable run artifacts. “Harness driver” can remain an internal implementation term, but it should not be the first thing a new reader sees. ## Desired product framing Ward should present itself as the runtime/control layer above coding agents: ```text Human / Director → Ward → contained agent worker → repo / issue / workflow system ``` Ward owns: * launch context * containment * agent-driver selection * issue/work-item lifecycle * repo access * policy/audit integration * workflow progression * outcome reconciliation The agent owns: * code reasoning * implementation * local tool use inside the container * commit/merge/push behavior within the granted workflow The key positioning distinction: ```text Not: “Ward tests agents.” Yes: “Ward drives agents through real engineering work safely enough to use live.” ``` ## Scope ### 1. Rename the external category Update README/docs language so Ward is not primarily described as a “harness driver.” Proposed external category: ```text guarded coding-agent execution layer ``` Possible README opener: ```markdown # ward Ward is a guarded execution layer for coding agents. It launches subscription-authenticated agent CLIs into ephemeral, least-access containers; drives them through issue-to-merge workflows; and records the work behind cli-guard policy, audit, and repo-scoped credentials. Internally, Ward is a manifest-backed harness driver: it knows how to launch Claude Code, Codex, OpenCode, Goose, and future coding agents through their own CLI dialects. ``` The term `harness driver` should remain valid in lower-level docs where the adapter/launcher implementation is discussed. #### Acceptance criteria * README first sentence no longer says only “ward is a harness driver.” * README explains Ward as a guarded execution layer for coding agents. * “Harness driver” is preserved as an internal architecture term. * Docs consistently distinguish: * external product category * internal driver implementation * underlying cli-guard policy/audit engine --- ### 2. Finish manifest-backed adapter lookup Ward already has the right direction: the fleet manifest should be the single source of per-agent divergence. The goal is to remove remaining hardcoded driver switches and make the launcher consume the manifest/registry consistently. Today the fleet records: * agent name * binary * context level * stream mode * auth mode * argv dialects * model/endpoint metadata for some agents The desired state is: ```text fleet manifest → parsed agent registry → launcher projection → container env → preflight/headless/interactive argv ``` No launch-path behavior should require hardcoded `switch mode { claude, codex, opencode, goose }` logic unless it is explicitly transitional and pinned by tests. #### Expand the adapter model Current manifest fields are launch-shape oriented. Add capability-shape fields where useful: ```yaml capabilities: preflight: true | false headless: true | false interactive: true | false stream: stream-json | stdout | none resume: true | false supports_images: true | false supports_mcp: inherited | native | none auth_source: host | container | none ``` Exact schema can differ, but the distinction should be clear: * `argv` describes how to invoke the agent. * `capabilities` describes what Ward may expect from that agent. #### Acceptance criteria * Remaining driver-specific switches in launch/compute paths are eliminated or isolated behind a manifest-backed registry. * `agentBinary`, `contextLevel`, `hostPreflightArgv`, stream handling, and auth shape derive from the fleet/adapter registry. * Tests pin current Claude/Codex/OpenCode/Goose behavior before and after migration. * Adding a new driver should require manifest/config changes and tests, not scattered Go switch edits. * Error messages name the manifest/registry source when an agent is malformed or unsupported. --- ### 3. Add workflow modes Ward currently centers the fast path: ```text issue → contained engineer → commit → merge to main → push → close issue ``` That is valid for personal/high-trust repos, but it should not be the only conceptual workflow. Teams will expect different landing policies. Add explicit workflow modes. Candidate modes: ```text direct-main pr patch-only ``` #### `direct-main` Current behavior. The agent may carry the issue through commit, merge to main, push, and close. Intended for: * solo repos * trusted automation repos * fast internal loops * low-review surfaces #### `pr` The agent carries the work to a branch/PR instead of landing directly. Expected lifecycle: ```text issue → branch → commit → push branch → open PR → report PR ``` Follow-up loops may handle: * CI failure * review comments * requested changes * merge after approval This can start minimal. The first slice does not need to solve all review automation. #### `patch-only` The agent produces a patch/diff/artifact but receives no push authority. Expected lifecycle: ```text issue → contained run → patch artifact → comment/report ``` Useful for: * external repos * untrusted targets * experiments * high-risk work * future provider abstraction #### Interface sketch Possible CLI surface: ```bash warded engineer #98 --workflow direct-main warded engineer #98 --workflow pr warded engineer #98 --workflow patch-only ``` Possible config default: ```yaml agent: workflow: direct-main ``` or: ```yaml workflows: default: direct-main ``` #### Acceptance criteria * Workflow mode is explicit in plan/print output. * Workflow mode is visible in container labels/env or run metadata. * Seed prompt/done condition changes based on workflow. * `direct-main` preserves existing behavior. * `pr` does not instruct the agent to merge directly to main. * `patch-only` does not grant push authority or instruct the agent to push. * Docs explain which workflow mode is appropriate for which trust level. --- ### 4. Continue abstracting Forgejo as a provider boundary Forgejo-first is correct for the current fleet, but Forgejo should not define Ward’s architecture. Ward needs a provider boundary around work items and source control operations. The current system is issue/Forgjo-shaped: * parse issue refs * read issue title/body/comments * reserve with comments * post outcomes * close issue * list repo/org backlog * expand org scope * clone/push against Forgejo remotes That should be abstracted behind provider concepts. #### Work item provider Sketch: ```go type WorkItemProvider interface { ParseRef(raw string) (WorkRef, error) Read(ctx context.Context, ref WorkRef) (WorkItem, error) ReadThread(ctx context.Context, ref WorkRef) ([]Comment, error) Reserve(ctx context.Context, ref WorkRef, run RunRef) error Release(ctx context.Context, ref WorkRef, run RunRef) error Comment(ctx context.Context, ref WorkRef, body string) error Close(ctx context.Context, ref WorkRef, resolution CloseResolution) error } ``` #### SCM provider Sketch: ```go type SCMProvider interface { CloneURL(repo RepoRef) string PushURL(repo RepoRef) string OpenPR(ctx context.Context, req PullRequestRequest) (PullRequestRef, error) ReadCI(ctx context.Context, ref ChangeRef) (CIStatus, error) Merge(ctx context.Context, ref ChangeRef, strategy MergeStrategy) error } ``` Exact interfaces should evolve from current code rather than be imposed wholesale. The important boundary is: ```text Ward workflow engine → provider interface → Forgejo implementation ``` not: ```text Ward workflow engine → Forgejo everywhere ``` #### Acceptance criteria * Forgejo-specific parsing/commenting/listing behavior is progressively isolated behind provider-shaped functions or interfaces. * Existing Forgejo behavior remains unchanged. * New workflow-mode work does not deepen Forgejo coupling. * Public docs refer to “work items” or “issues” where generic, and “Forgejo issues” only where implementation-specific. * Future GitHub/GitLab support is architecturally plausible without rewriting the driver. ## Explicit non-goals ### Velocity metrics Do not include velocity instrumentation in this issue. Potential future metrics such as time-to-land, human intervention count, redispatch count, blocked rate, salvage rate, and wall-clock-to-land are intentionally out of scope. ### Model-proxy integration Do not add model-proxy integration here. Ward should remain focused on the top driver layer for this parent issue. ### Read-only credential hardening Do not prioritize dispatch-only credentials or deeper read-only credential isolation in this issue. Known soft edges may remain documented, but this parent does not track fixing them. ## Suggested breakout issues * Reword README and top-level docs around “guarded coding-agent execution layer.” * Replace remaining driver switches with manifest-backed adapter lookup. * Add agent capability fields to the fleet manifest. * Add `--workflow direct-main|pr|patch-only`. * Implement workflow-specific seed prompts and done conditions. * Implement `patch-only` as the first non-direct workflow. * Implement `pr` as branch + PR creation, without review-loop automation. * Extract Forgejo work-item operations behind a provider boundary. * Extract SCM operations behind a provider boundary. * Update docs to distinguish product category, driver internals, workflows, and providers. ## Done when Ward’s public story reads as: > Ward is a guarded execution layer for coding agents. and the implementation supports that story by having: * manifest-backed agent driver selection, * explicit workflow modes, * and a Forgejo implementation behind a provider seam. At that point, “harness driver” remains true, but it is no longer the category Ward is trying to win. ### Alternatives considered _No response_ ### Before filing - [x] I searched existing issues and this is not a duplicate. - [x] This stays within ward's scope (the dev-verb gate / agent driver), not a personal-infra or downstream-repo verb.
Author
Owner
the ecosystem: https://github.com/kingjulio8238/swarm-code https://github.com/dsifry/metaswarm https://github.com/nwiizo/ccswarm https://github.com/stravu/crystal https://github.com/nutthouse/tutti https://github.com/AgentWrapper/agent-orchestrator https://github.com/RunMaestro/Maestro https://github.com/smtg-ai/claude-squad https://github.com/asheshgoplani/agent-deck https://github.com/johannesjo/parallel-code https://github.com/preset-io/agor
Member

🔒 Reserved by ward agent --driver claude — container engineer-claude-ward-508 on host KAI-DESKTOP-TOWER is carrying this issue (reserved 2026-07-03T06:33:52Z). Concurrent ward agent runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); --force overrides.

— Claude (she/her), via ward agent

<!-- ward-agent-reservation --> 🔒 Reserved by `ward agent --driver claude` — container `engineer-claude-ward-508` on host `KAI-DESKTOP-TOWER` is carrying this issue (reserved 2026-07-03T06:33:52Z). Concurrent `ward agent` runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); `--force` overrides. <!-- ward-agent-signature --> — Claude (she/her), via `ward agent`
Author
Owner

WARD-OUTCOME: done - shipped --workflow direct-main|pr|patch-only and reframed ward's external category as a guarded coding-agent execution layer; deferred scopes 2 & 4 filed as #552 and #553.

Candid retro: this "parent" was really four issues wearing one hat, with ten breakouts listed in its own body. So I didn't try to do all of it - I landed the two slices that are concrete and testable end to end (workflow modes + the README/architecture reframe) and filed the two genuine refactors as their own issues (#552 capability manifest fields, which needs an upstream cli-guard fleetconfig change; #553 the WorkItem/SCM provider boundary). That felt like the honest read of a tracking issue rather than a cop-out.

The part that fought back was the reaper. Adding a --workflow patch-only flag that then let the deterministic reaper force-push main on teardown would have been a quiet footgun - the flag would lie. So the reaper now reads WARD_WORKFLOW and preserves a pr/patch-only run's residual work on a salvage branch instead of landing it. That coupling wasn't obvious from the issue text; it's the bit I'm most glad I caught.

Two smaller frictions: the code-comments pre-commit cap made me reflow a handful of unrelated Windows/Unix-guard comment blocks to land green without --no-verify, and those promptly collided on merge with a sibling branch that had reflowed the exact same lines (took theirs). And FEATURES.md brushed its char cap after the merge, so my bullet got trimmed twice.

Confidence: high on the seam itself - flag parse, seed carry-clause, reflection landing phrase, env, label, --print, and the reaper guard are all unit-tested, and direct-main is a thin wrapper so existing behavior is byte-for-byte unchanged (the old seed tests still pass untouched). Lower, unavoidably, on the live pr/patch-only container runs, since I can't drive a real agent container from here - the contract is enforced at the prompt + reaper layers, not yet at the credential layer.

Rough edges I wrote into docs/agent-workflow.md and worth a follow-up: patch-only is prompt+reaper enforced, not credential-scoped (that's the deferred read-only-credential hardening), and a pr/patch-only reaper hold currently reads as a slightly noisy salvage rather than a clean "held by policy" outcome.

WARD-OUTCOME: done - shipped `--workflow direct-main|pr|patch-only` and reframed ward's external category as a guarded coding-agent execution layer; deferred scopes 2 & 4 filed as #552 and #553. Candid retro: this "parent" was really four issues wearing one hat, with ten breakouts listed in its own body. So I didn't try to do all of it - I landed the two slices that are concrete and testable end to end (workflow modes + the README/architecture reframe) and filed the two genuine refactors as their own issues (#552 capability manifest fields, which needs an upstream cli-guard `fleetconfig` change; #553 the WorkItem/SCM provider boundary). That felt like the honest read of a tracking issue rather than a cop-out. The part that fought back was the reaper. Adding a `--workflow patch-only` flag that then let the deterministic reaper force-push `main` on teardown would have been a quiet footgun - the flag would lie. So the reaper now reads `WARD_WORKFLOW` and preserves a pr/patch-only run's residual work on a salvage branch instead of landing it. That coupling wasn't obvious from the issue text; it's the bit I'm most glad I caught. Two smaller frictions: the `code-comments` pre-commit cap made me reflow a handful of unrelated Windows/Unix-guard comment blocks to land green without `--no-verify`, and those promptly collided on merge with a sibling branch that had reflowed the exact same lines (took theirs). And FEATURES.md brushed its char cap after the merge, so my bullet got trimmed twice. Confidence: high on the seam itself - flag parse, seed carry-clause, reflection landing phrase, env, label, `--print`, and the reaper guard are all unit-tested, and direct-main is a thin wrapper so existing behavior is byte-for-byte unchanged (the old seed tests still pass untouched). Lower, unavoidably, on the live pr/patch-only container runs, since I can't drive a real agent container from here - the contract is enforced at the prompt + reaper layers, not yet at the credential layer. Rough edges I wrote into docs/agent-workflow.md and worth a follow-up: patch-only is prompt+reaper enforced, not credential-scoped (that's the deferred read-only-credential hardening), and a pr/patch-only reaper hold currently reads as a slightly noisy salvage rather than a clean "held by policy" outcome.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
coilyco-flight-deck/ward#508
No description provided.