Skip to content

fix(harness): bind planning gate approval to the review-cycle epoch - #164

Open
Christiantyemele wants to merge 2 commits into
mainfrom
fix/plan-epoch-gate-freshness
Open

fix(harness): bind planning gate approval to the review-cycle epoch#164
Christiantyemele wants to merge 2 commits into
mainfrom
fix/plan-epoch-gate-freshness

Conversation

@Christiantyemele

Copy link
Copy Markdown
Collaborator

Problem

FORGE could escalate to building by consuming a stale or pre-seeded planning-gate approval from a prior cycle, without SENTINEL having reviewed the current plan.

Observed live: a 4-day-old planning gate approval (legacy record, no epoch, timestamp Aug-14) was treated as live authorization, and FORGE escalated to building — SENTINEL was never spawned to review that plan.

Root cause: the harness enforced that an approval exists (GETDEL single-use) but had no way to bind an approval to the current plan/review cycle. A leftover or manually-seeded approval could never be distinguished from a fresh one.

Fix

Bind the gate approval to a per-ticket review-cycle epoch in crates/openflows-harness/src/store.rs:

  1. status set planning advances the ticket's plan_epoch (Redis INCR) and clears any prior planning-gate approval, opening a fresh review window. No stale approval can survive into a new cycle.
  2. gate approve records the current plan_epoch inside the GateApproval and refuses to approve when no cycle is open (epoch missing) — SENTINEL cannot seed an approval for a cycle FORGE never opened.
  3. status set out of planning (the GETDEL consume path) now rejects the transition when the consumed approval's plan_epoch ≠ the ticket's current epoch. Legacy/pre-seeded approvals (epoch 0) can no longer authorize a build; SENTINEL must re-review the current plan.
  4. gate status prints the approval's epoch vs. the ticket's current epoch and flags stale approvals with a warning, so humans/NEXUS can audit freshness.

GateApproval.plan_epoch uses #[serde(default)] for backward compatibility with pre-epoch records (they deserialize as stale, epoch 0).

Verification

  • cargo test -p openflows-harness — 14 tests pass (incl. 3 new: staleness predicate, serde round-trip with epoch, legacy-record defaults to stale).
  • cargo clippy -p openflows-harness --all-targets — clean.
  • cargo fmt — clean.
  • End-to-end against live Redis, simulated the exact reported bug: seeding a legacy approval (no epoch) then status set buildingCannot transition ... gate approval is stale (approval plan_epoch=0, current plan_epoch=2). SENTINEL must re-review the current plan ... and gate status prints ⚠ ... STALE ... It will NOT authorize a transition. Legitimate flows (fresh planning → sentinel approve → build; re-plan → re-review → build) continue to succeed.

Scope

Only crates/openflows-harness/src/store.rs is changed. NEXUS notification logic (which checks for the presence of a planning gate to decide when to wake FORGE) remains correct: signaling planning clears the gate → NEXUS waits for SENTINEL; SENTINEL approval re-creates it → NEXUS resumes FORGE.

@gitar-bot

gitar-bot Bot commented Aug 18, 2026

Copy link
Copy Markdown

Gitar is working

Gitar

FORGE could escalate to 'building' by consuming a stale or pre-seeded
gate approval from a prior cycle, without SENTINEL having reviewed the
current plan. This was observed when a 4-day-old planning approval
(legacy, no epoch) authorized a fresh build.

Enforce cycle freshness in the shared store:
- status set planning advances a per-ticket plan_epoch (INCR) and clears
  any prior planning-gate approval, opening a fresh review window.
- gate approve records the current plan_epoch in the GateApproval and
  refuses to approve when no cycle is open (epoch missing).
- status set out of planning (GETDEL path) now rejects the transition
  when the consumed approval's plan_epoch does not match the current
  epoch, so legacy/pre-seeded approvals (epoch 0) cannot authorize a
  build; SENTINEL must re-review the current plan.
- gate status prints the approval's epoch vs. the ticket's current epoch
  and flags stale approvals (warning) so humans/NEXUS can audit.

GateApproval.plan_epoch uses #[serde(default)] for backward
compatibility with pre-epoch records (they deserialize as stale).
@Christiantyemele
Christiantyemele force-pushed the fix/plan-epoch-gate-freshness branch from 9dd926c to f9b2d41 Compare August 18, 2026 16:20
@greptile-apps

greptile-apps Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR binds planning approvals to per-ticket epochs and adds durable approval tracking and bypass detection across the harness and controller.

  • Advances the planning epoch when a review cycle opens and validates approval freshness during gated transitions.
  • Adds controller-side detection and escalation for completion artifacts produced without current-cycle approval.
  • Updates identity, Coder provisioning, tenant configuration, and associated documentation.

Confidence Score: 3/5

The PR is not yet safe to merge because existing planning tickets can remain blocked and concurrent cycle opening can discard a fresh approval.

Existing planning records without an epoch are still rejected during approval, while the separate epoch increment and gate cleanup operations can delete an approval written for the newly opened cycle.

Files Needing Attention: crates/openflows-harness/src/store.rs

Important Files Changed

Filename Overview
crates/openflows-harness/src/store.rs Introduces epoch-bound planning approvals, durable approval markers, freshness reporting, and transition validation.
crates/agent-forge/src/lib.rs Detects unapproved completion artifacts and routes planning-gate bypasses to NEXUS.
crates/agent-nexus/src/lib.rs Adds current-cycle approval checks and moves bypassed tickets to human intervention.
crates/config/src/state.rs Adds the shared gate-bypass routing action.
binary/src/bin/agentflow.rs Connects the new gate-bypass action from FORGE back to NEXUS.

Sequence Diagram

sequenceDiagram
    participant F as FORGE
    participant H as Harness
    participant R as Redis
    participant S as SENTINEL
    participant N as NEXUS
    F->>H: status set planning
    H->>R: INCR plan_epoch
    H->>R: clear previous gate
    N->>S: request plan review
    S->>H: gate approve planning
    H->>R: write epoch-bound gate
    H->>R: write durable approval marker
    F->>H: status set building
    H->>R: GETDEL gate
    H->>R: read current plan_epoch
    H-->>F: allow only when epochs match
Loading

Reviews (2): Last reviewed commit: "feat(): external auth" | Re-trigger Greptile

Comment thread crates/openflows-harness/src/store.rs
Comment thread crates/openflows-harness/src/store.rs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant