Skip to content

Instantly share code, notes, and snippets.

@ericjuta
Created April 8, 2026 00:25
Show Gist options
  • Select an option

  • Save ericjuta/c141b73c613c4602dfcf9cf6c3091a62 to your computer and use it in GitHub Desktop.

Select an option

Save ericjuta/c141b73c613c4602dfcf9cf6c3091a62 to your computer and use it in GitHub Desktop.
openai symphony with openclaw orchestrator - human Vs machine readable operator review

Ticket Machine State

Status: draft design spec
Audience: Brier operators, OpenClaw reducer implementers, Symphony workflow authors

Purpose

This document defines the ticket state model that sits between the human tracker and the machine evidence graph.

The key idea is:

  • humans should see a small, legible FSM
  • automation should operate on a richer evidence vector

The Brier case study showed that the human tracker state alone is not enough for honest automation. A ticket could be:

  • In Progress in Linear while the PR was already ready to merge
  • Done in repo truth while still stale in Linear
  • merged in GitHub while runtime proof was still missing
  • technically claimed by Symphony while no meaningful work had happened yet

Human FSM

The recommended human-facing workflow is:

  1. Backlog
  2. Todo
  3. In Progress
  4. Review
  5. Merging
  6. Rework
  7. Done

Notes

  • Review is the canonical handoff name.
  • Human Review should be treated as a historical alias only during migration.
  • Blocked is best treated as an orthogonal machine or label concept, not necessarily a primary tracker state.
  • Done means tracker closure, not automatically runtime proof.

Why the FSM is not enough

The human FSM is intentionally coarse. That is good for operators. It is bad as the only automation substrate.

The machine needs to know facts such as:

  • was the ticket claimed?
  • is there a workspace?
  • has a meaningful diff appeared?
  • does a PR exist?
  • are required checks green?
  • was the PR merged?
  • was Linear reconciled?
  • does runtime proof exist?
  • is the lane stalled?

Those are not human-facing states. They are evidence fields.

Canonical machine evidence vector

The reducer should track at least the following dimensions per ticket.

Dimension Example fields Why it exists
Identity issue_id, issue_identifier, repo, project_slug stable correlation
Planning state_human, dependencies_satisfied, spec_node_ids what should be happening
Claim/execution claimed_at, worker_id, workspace_path, session_id whether Symphony really picked it up
Workspace progress first_meaningful_diff_at, changed_files, workpad_seen bootstrap vs real work
Git publication branch, commit_count, latest_commit_sha, branch_pushed_at code artifact evidence
PR status pr_number, pr_state, pr_url, review_decision review surface truth
Check status required_checks, checks_green, failing_checks, last_check_update_at merge gate truth
Merge status merged_at, merge_commit_sha what actually landed
Tracker reconciliation tracker_reconciled_at, tracker_state_matches_repo prevent Linear drift
Runtime proof runtime_required, runtime_proved_at, runtime_proof_ids code truth vs live truth
Blockers blocker_kind, blocker_summary, needs_human, retry_count honest escalation
Freshness last_event_at, stale_after_s, stalled dead-lane detection

Minimal JSON shape

A reducer-owned ticket record can look like this:

{
  "issue": {
    "id": "linear:ERICJUT-23",
    "identifier": "ERICJUT-23",
    "repo": "ericjuta/brier",
    "state_human": "In Progress",
    "spec_node_ids": [
      "spec:mlb-struct/request-efficiency"
    ]
  },
  "execution": {
    "worker": "symphony",
    "claimed_at": "2026-04-04T13:12:00Z",
    "workspace_path": "/home/ericjuta/code/brier-symphony-workspaces/ERICJUT-23",
    "session_id": "019d..."
  },
  "git": {
    "branch": "ericjut-23-request-efficiency",
    "latest_commit_sha": "abc123",
    "branch_pushed_at": "2026-04-04T13:28:00Z"
  },
  "pr": {
    "number": 20,
    "state": "OPEN",
    "checks_green": true,
    "merged_at": null
  },
  "runtime": {
    "required": true,
    "proved_at": null,
    "proof_ids": []
  },
  "freshness": {
    "last_event_at": "2026-04-04T13:31:22Z",
    "stale_after_s": 2700,
    "stalled": false
  },
  "blocker": null
}

Derived machine labels

The reducer should derive machine labels from the evidence vector instead of writing them as primary truth.

Useful derived labels include:

  • claimed
  • bootstrap_only
  • active_with_diff
  • pr_open
  • review_ready
  • review_blocked
  • mergeable
  • merged_awaiting_tracker_reconcile
  • runtime_proof_pending
  • stalled
  • blocked_needs_human
  • complete

These are for supervision and frontier selection. They should not replace the human FSM.

State interpretation rules

Todo

Expected evidence:

  • dependency-safe
  • not yet claimed
  • no current branch/PR required

Bad smell:

  • Todo with an attached live workspace and no recent events can mean the worker never moved the ticket to In Progress

In Progress

Expected evidence:

  • claim or workspace exists
  • at least one of: workpad, meaningful diff, commit, PR

Bad smells:

  • long-running In Progress with no meaningful diff
  • repeated retries with the same blocker
  • token burn without branch or commit evidence

Review

Expected evidence:

  • PR exists
  • validation is green or the remaining failures are explicitly understood
  • review comments have been swept
  • workpad or equivalent progress record is current

Bad smells:

  • Review with no PR
  • Review while required checks are still red for unresolved reasons
  • Review long after merge already happened

Merging

Expected evidence:

  • branch is approved and actively being landed
  • a merge operation is actually in flight

Bad smell:

  • long-lived Merging

This state should normally be transient.

Rework

Expected evidence:

  • actionable review feedback or explicit reopen
  • a real diff loop is happening again

Bad smell:

  • Rework without any active reviewer feedback or blocker note

Done

Expected evidence:

  • merge commit exists, or the relevant repo landing proof exists for the ticket type
  • Linear is reconciled
  • if runtime proof is part of acceptance, that proof also exists

Bad smell:

  • Done with no merge proof
  • Done while runtime reconcile is still clearly pending for a runtime-affecting slice

Invalid combinations and reducer responses

The reducer should treat these as drift conditions.

Combination Why invalid Reducer response
Done but no merged artifact tracker got ahead of repo truth emit drift event; reopen or flag
Review with no PR handoff state lacks code artifact downgrade to active drift or flag
In Progress with no claim/diff/commit for too long likely ghost lane mark stalled; surface blocker
merged PR but tracker still In Progress tracker drifted behind repo truth reconcile or raise exact drift
merged and tracker done but runtime proof missing for required ticket code closure != acceptance closure keep parent spec node open
queue dry but spec nodes still incomplete current tranche complete, mission not complete frontier selector must mint next work or surface blocker

Freshness model

Staleness should be computed by stage, not globally.

Suggested defaults:

Stage Example stale threshold
claimed, no workpad or diff 15-30 minutes
diff started, no commit 45-90 minutes
PR open, checks not started 15-30 minutes
checks running CI-provider-dependent
merged, tracker not reconciled 5-15 minutes
runtime-proof pending ticket-specific

These are policy values, not hard laws. They should stay configurable.

Blockers are orthogonal

A blocker should not require inventing a separate top-level tracker state. The machine model should capture:

  • blocker_kind
    • auth
    • missing secret
    • flaky CI
    • runtime drift
    • dependency not ready
    • review feedback
    • unknown
  • needs_human
  • retry_count
  • last_blocked_at
  • blocker_summary
  • unblock_action

That lets the reducer stay honest without exploding the human FSM.

Runtime-required tickets

Some tickets can be closed at merge. Others cannot.

The machine model therefore needs a boolean such as:

  • runtime.required

Examples where runtime proof is likely required:

  • alert delivery
  • live ingestion behavior
  • service wiring
  • scheduler behavior
  • endpoint exposure
  • deployment topology changes

Examples where runtime proof may be optional:

  • docs-only changes
  • pure refactors
  • fixtures/tests only
  • internal scoring docs that do not claim live behavior changed

Historical alias handling

During migration, the reducer should normalize aliases:

  • Human Review -> Review
  • In Review -> Review when used as the human handoff equivalent

The stored canonical human state should still be Review.

Brier case-study examples

Example 1: merged PR, stale tracker

Observed shape:

  • PR merged cleanly
  • tracker still active
  • Symphony could reopen or continue stale work

Machine interpretation:

  • merge_commit_sha present
  • tracker_state_matches_repo = false
  • derived label: merged_awaiting_tracker_reconcile

Example 2: worker active, no real work yet

Observed shape:

  • session existed
  • tokens were being burned
  • only bootstrap fingerprint was present

Machine interpretation:

  • claim exists
  • first_meaningful_diff_at = null
  • derived label: bootstrap_only

Example 3: repo fixed, runtime still stale

Observed shape:

  • cadence fix merged on master
  • live Phoenix workers still came from old Symphony workspaces

Machine interpretation:

  • repo artifact complete
  • runtime proof missing
  • derived label: runtime_proof_pending

Summary

The ticket model should stay split:

  • human FSM for operator legibility
  • machine evidence vector for automation honesty

That split is what makes event-driven orchestration realistic instead of performative.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment