Skip to content

Disable cargo publish for all crates - #164

Merged
getappz merged 4 commits into
masterfrom
ci/disable-publish
Jul 13, 2026
Merged

getappz merged 4 commits into
masterfrom
ci/disable-publish

Conversation

@getappz

@getappz getappz commented Jul 13, 2026 •

Copy link
Copy Markdown
Owner

Closes #163

Add \publish = false\ to root + all 6 workspace crate \Cargo.toml\ files.

We have installer scripts — cargo publish + binstall publish are unused.

Summary by CodeRabbit

  • Chores
    • Updated crate version metadata across multiple components.
    • Marked several components as not intended for registry publishing to avoid accidental releases.
    • Streamlined release automation to focus on creating version-bump PRs and removed the use of a registry publish token.
    • Made PPA publishing conditional so it only runs when the required GPG key is configured.
    • Shortened the release task description to reflect the new streamlined behavior.

@getappz getappz added the tech-debt Internal refactoring / cleanup, no user-facing feature label Jul 13, 2026
@coderabbitai

coderabbitai Bot commented Jul 13, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Cargo package versions were adjusted in the root package and six workspace crates. Manifests now explicitly disable publishing, internal path dependencies no longer specify versions, and release workflows update registry credentials, PPA dispatch, and release task documentation.

Changes

Publishing metadata and release automation

Layer / File(s) Summary
Workspace manifest publishing controls
Cargo.toml, crates/*/Cargo.toml
Package versions and publish = false settings were updated across the root package and workspace crates; internal path dependencies no longer include explicit version constraints.
Release publishing configuration
.github/workflows/release-plz.yml, .github/workflows/release.yml, mise.toml
Release-PR automation no longer receives CARGO_REGISTRY_TOKEN, PPA dispatch requires PPA_GPG_KEY, and the release task description now only describes creating a version-bump PR.

Estimated code review effort: 1 (Trivial) | ~5 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is missing the required Summary, Test plan, and Notes for reviewers sections from the template. Add the template sections: Summary, Test plan with the three checklist items, and Notes for reviewers covering risk areas and backwards compatibility.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly reflects the main change: disabling Cargo publishing for the workspace crates.
Linked Issues check ✅ Passed The PR adds publish=false to the root and all six workspace crates and preserves the requested publishing cleanup.
Out of Scope Changes check ✅ Passed No clearly unrelated changes are evident beyond the publishing and workflow cleanup requested by the issue.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ci/disable-publish

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/release.yml:
- Line 266: Update the job-level condition using secrets.PPA_GPG_KEY so it no
longer references the unavailable secrets context. Move the key-presence check
into the relevant dispatch step, or expose it through a prior job output and
reference that output in the job condition.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: b7812c6e-62ec-43f3-8b55-6c9518ccf07c

📥 Commits

Reviewing files that changed from the base of the PR and between 9c8c7cb and a6984cf.

📒 Files selected for processing (3)
  • .github/workflows/release-plz.yml
  • .github/workflows/release.yml
  • mise.toml
💤 Files with no reviewable changes (1)
  • .github/workflows/release-plz.yml

Comment thread .github/workflows/release.yml Outdated
… is disabled

skill-registry still required agent-registry ^0.1.1 while this branch downgraded
agent-registry's own version to 0.1.0, breaking dependency resolution. Since
every crate here is publish = false, version reqs on path-only deps serve no
purpose - drop them everywhere instead of keeping numbers in sync forever.

Also moves the PPA_GPG_KEY secret check from the job-level if: down to the
step, per CodeRabbit: secrets are not reliable in job-level if: conditionals.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/release.yml:
- Line 271: Update the step condition in the release workflow to expose
PPA_GPG_KEY through the step’s env configuration, then test env.PPA_GPG_KEY in
the if expression instead of referencing the secrets context directly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 47d23f88-20a2-47f1-ae4a-f8eae170186e

📥 Commits

Reviewing files that changed from the base of the PR and between a6984cf and bf4e794.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • .github/workflows/release.yml
  • Cargo.toml
  • crates/skill-registry/Cargo.toml
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/skill-registry/Cargo.toml

actions: write # gh workflow run
steps:
- name: Dispatch ppa-publish workflow
if: secrets.PPA_GPG_KEY != ''

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major

The secrets context is still invalid in this if expression.

Moving the condition to the step does not make secrets.PPA_GPG_KEY available to if. Expose the secret through env first, then check env.PPA_GPG_KEY:

Proposed fix
   trigger-ppa-publish:
     name: Trigger PPA publish
     needs: release
     runs-on: ubuntu-latest
+    env:
+      PPA_GPG_KEY: ${{ secrets.PPA_GPG_KEY }}
     permissions:
       actions: write
     steps:
       - name: Dispatch ppa-publish workflow
-        if: secrets.PPA_GPG_KEY != ''
+        if: env.PPA_GPG_KEY != ''

[actionlint] reports this same context-availability problem, so the workflow remains invalid.

🧰 Tools
🪛 actionlint (1.7.12)

[error] 271-271: context "secrets" is not allowed here. available contexts are "env", "github", "inputs", "job", "matrix", "needs", "runner", "steps", "strategy", "vars". see https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability for more details

(expression)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release.yml at line 271, Update the step condition in the
release workflow to expose PPA_GPG_KEY through the step’s env configuration,
then test env.PPA_GPG_KEY in the if expression instead of referencing the
secrets context directly.

Source: Linters/SAST tools

@getappz
getappz merged commit 6e7f0e8 into master Jul 13, 2026
16 checks passed
@getappz
getappz deleted the ci/disable-publish branch July 13, 2026 08:43
getappz added a commit that referenced this pull request Jul 13, 2026
…ict with ci/disable-publish

Root Cargo.toml conflicted on the dependency block: master (via #164) had
already dropped version pins from internal path deps. Applied the same
treatment to the newly added agentflare-backend/db_kit deps, and added
publish = false to both crates' own Cargo.toml for consistency.
getappz added a commit that referenced this pull request Aug 21, 2026
…ting two agents race the same worktree (#582)

* fix: orphan reconciliation never killed a still-alive subprocess, letting two agents race the same worktree

A daemon restart doesn't kill an already-spawned agent subprocess tree —
it's deliberately placed in its own process group (cmd.process_group(0),
needed so kill_tree's targeted kill works during normal timeouts), so it
survives as a genuine orphan invisible to the new daemon. reconcile_orphaned_running
only updated the DB row and released the claim, then immediately restored
ready-for-work — letting a fresh dispatch race the still-running orphan
into editing the same files concurrently. Hit in production 2026-08-21
(item #164): a claude-code and an opencode process both ended up bound to
the same worktree, corrupting it.

Kill anything still touching the item's worktree (pgrep -f against the
worktree path, robust to any process-tree shape) before releasing the
claim or relabeling ready-for-work.

Agentflare-Agent: claude-code
Agentflare-Branch: docs/opencode-model-mapping-fallback

* fix: kill_processes_touching_worktree wasn't cross-platform (Windows had no pgrep)

The original fix used pgrep -f directly, which doesn't exist on Windows
(caught by CI: build (windows-latest) failed). Split into #[cfg(unix)]
(pgrep, unchanged) and #[cfg(windows)] (Get-CimInstance Win32_Process
CommandLine match via PowerShell) implementations. Gated the new test
#[cfg(unix)] since its yes-based orphan simulation isn't portable.
Trimmed comments to stay under the LOC gate.

Agentflare-Agent: claude-code
Agentflare-Branch: fix/orphan-reconcile-kill-live-process

---------

Co-authored-by: shiva <shiva@gosysinfo.tech>
getappz added a commit that referenced this pull request Aug 24, 2026
…ck + workflow-store smoke test) (#596)

* feat: add dispatch preflight/init validation step (item #164)

Duplicate-work detection (pre-claim): before dispatching an item,
find_duplicate_pr searches GitHub for a PR already carrying the item's
'for item #N' marker. A merged match self-heals the item to completed
and cleans up its worktree instead of letting a redispatch re-do
already-merged work (the near-miss from items #122/#156, where tracked
state fell out of sync with a merged PR). An open match skips dispatch
and flags for human review instead of racing a second PR.

Workflow-store smoke test: flare_workflow::smoke_test does a real
save/delete/load round-trip against the actual on-disk SqliteStore
schema. Wired into daemon boot (dashboard::server::run) and into
dev_install::run via a new hidden 'daemon workflow-store-smoke-test'
subcommand, run against the freshly built binary right after a binary
swap -- the exact trigger (item #576) that let a broken delete_state
go undetected for ~33h. On failure, refuses dispatch instead of letting
every claimed item retry-and-fail silently into a stuck state.

src/cli/work.rs is frozen at the LOC gate's 2100-line limit, so the new
duplicate-PR logic and its tests live in their own included files
(work_duplicate_pr.rs, work_duplicate_pr_tests.rs) rather than growing
work.rs itself.

Agentflare-Agent: claude-code
Agentflare-Branch: task/164-dispatch-preflight-validation
Agentflare-Item: 164

* fix review findings: duplicate-PR selection, claim/completion error handling, smoke-test ordering

Addresses 6 CodeRabbit findings on PR #596, all independently verified
against the actual code before fixing:

- pick_duplicate_pr: a closed-but-unmerged PR was treated the same as a
  genuinely open one, permanently blocking a legitimate redispatch.
  Now filters to merged-or-open only.
- handle_duplicate_pr: a failed/unconfirmed mark_completed was silently
  reported as success (comment posted, claim released, exit 0). Now
  returns a retryable failure and leaves the claim armed instead.
- handle_duplicate_pr: item_release's result was discarded and
  claim_guard was disarmed unconditionally, so a failed release left
  nothing to retry it. Now only disarms on confirmed release success.
- dashboard::server::run: engine().recover() ran before the workflow-store
  smoke test, so a broken store could still be touched by recovery before
  validation. Reordered so recovery is gated behind the smoke test too.
- dev_install::verify_workflow_store: used a blocking Command::status()
  with no timeout, unlike its sibling verify_runs. Now uses the same
  spawn/try_wait/kill-with-deadline pattern.
- github::pulls::find_by_item_marker: the search API call was
  unpaginated (GitHub's default page size is 30), so a matching PR
  beyond the first page would silently not be found. Now uses the
  existing get_paginated helper.

Also fixes the schema-mismatch regression test in sqlite_store.rs: it
put the intentional id/run_id mismatch on workflow_runs itself, so
write_state failed on save and delete_state's own failure path was
never actually exercised. Moved the mismatch to journal (write_state
never touches it for an empty smoke-test state) and strengthened the
assertion to confirm the failure comes from there.

New tests: pick_duplicate_pr_ignores_a_closed_unmerged_pr,
pick_duplicate_pr_selects_a_genuinely_open_pr_when_no_merged_match_exists.

Verified: cargo build, cargo test --bin agentflare (1548/1548 passing),
cargo test -p flare-workflow (all passing), cargo fmt --check, cargo
clippy (CI's exact flags), scripts/loc-gate.sh.

Agentflare-Agent: claude-code
Agentflare-Branch: task/164-dispatch-preflight-validation
Agentflare-Item: 164

* fix: gate work dispatch on successful pipeline registration/recovery

engine().register_workflow()/recover() failures were only logged --
the worker pool and both supervisor ticks still started regardless,
undermining the smoke-test gate's own fail-closed contract one level
up: dispatch could start against pipeline state that's already known
to be broken.

Also fixes a compile error from the prior commit: recover() returns
Result<Vec<WorkflowRunId>, WorkflowError>, not Result<(), _>.

Agentflare-Agent: claude-code
Agentflare-Branch: task/164-dispatch-preflight-validation
Agentflare-Item: 164

---------

Co-authored-by: shiva <shiva@gosysinfo.tech>
getappz pushed a commit that referenced this pull request Aug 25, 2026
…etry forever

DISPATCH_FAILURE_CAP only trips after 3 consecutive dispatch cycles with an
identical failure reason. An item whose job fails for a mix of different
reasons -- or orphans (daemon restart mid-job) and posts no failure marker
at all -- resets that streak every time, so the cap can never trip. Item
#164 hit 400+ dispatch cycles this way, only 2 of which ever landed on the
identical-reason cap.

Add a looser DISPATCH_FAILURE_CAP_ANY_REASON (6) that counts consecutive
non-success dispatch cycles regardless of reason, including unrecorded
(orphaned) ones. Wire it into handle_terminal_job_failure (clean-failure
path) alongside the existing identical-reason check, and into
restore_ready_for_work (the orphan-restart path in reconcile_orphaned_jobs,
which previously never applied any cap at all) so a job that keeps orphaning
across repeated daemon restarts also eventually lands on
needs-manual-dispatch instead of being unconditionally resurrected.

Split orphan_reconcile.rs's test module out to orphan_reconcile_tests.rs
(included via include!, mirroring cli::work's work_duplicate_pr_tests.rs
split) to stay under the LOC gate after the new coverage.

Agentflare-Agent: claude-code
Agentflare-Branch: fix/dispatch-failure-ceiling-any-reason
getappz added a commit that referenced this pull request Sep 12, 2026
…tries (#666)

Root-cause of item #164's 15h incident: diagnostic_suffix preferred stdout
over stderr, discarding real CLI error text; the only failure classifier
was rate-limiting, so an expired-auth failure fell through to
cooldown-and-retry against a credential that fails identically every time.

- diagnostic_suffix now always includes a non-empty stderr tail alongside
  stdout instead of only falling back to it when stdout is empty
- auth_runner::is_auth_expired + ExitKind::AuthExpired classify
  expired-auth failures distinctly from rate limits; the interactive
  retry loop now prompts for re-auth instead of rotating profiles
- cli::work::handle_auth_expired (split into work_auth_expiry.rs to stay
  under work.rs's frozen LOC limit) intercepts before classify_and_cooldown,
  fails the job immediately (fatal: true, no retry-budget burn), applies
  an idempotent auth-expired label, logs the alert to both stderr and the
  job's own log file, and reuses notify_human_gate for immediate alerting
- work_item_pipeline's sdd_loop map_err sites short-circuit their own
  RetryPolicy via StepResult::Failed instead of a generic Err

Agentflare-Agent: claude-code
Agentflare-Branch: task/173-implement-detect-and-surface-agent-auth
Agentflare-Item: 173
Agentflare-Session: d168de95-65a5-4e8c-b013-83e56df9cc97

Co-authored-by: shiva <shiva@gosysinfo.tech>
getappz added a commit that referenced this pull request Sep 12, 2026
…limit cooldown never fires for autonomous dispatch (#664)

* Both call sites (the two identified in the bug report as the root cause) are fixed, and there are no other callers of `finish_workflow_failed` left unpatched.

Summary of verification:
- Both `finish_workflow_failed` call sites in `execute_workflow` now fold the failing step's `last_error` into the error message, exactly as prescribed.
- `crates/flare-workflow` full test suite passes (I reran it, including the new `workflow_level_error_preserves_the_failed_steps_real_reason` regression test).
- The main `agentflare` binary compiles and its 3 `classify_and_cooldown` tests pass (I ran this myself — the implementer's own session ended without ever confirming this, having only started it as a background task and then stopping without waiting for the result, which is exactly the kind of unverified completion this process asks reviewers to catch).
- Fallback behavior (`state_store.load(...).ok()`) is safe if the store read fails — degrades to the generic message rather than panicking.
- No other `finish_workflow_failed` call sites were missed.

REVIEW_APPROVED

Agentflare-Agent: claude-code_2-1-268_agent
Agentflare-Branch: task/229-workflow-level-failure-discards-the-real
Agentflare-Item: 229-workflow-level-failure-discards-the-real

* wip(sdd-loop): task 0 checkpoint (#665)

Agentflare-Agent: claude-code_2-1-268_agent
Agentflare-Branch: task/219-borrow-notis-handoff-recursion-guard
Agentflare-Item: 219-borrow-notis-handoff-recursion-guard

Co-authored-by: shiva <shiva@gosysinfo.tech>

* fix(auth): detect and surface expired agent auth instead of silent retries (#666)

Root-cause of item #164's 15h incident: diagnostic_suffix preferred stdout
over stderr, discarding real CLI error text; the only failure classifier
was rate-limiting, so an expired-auth failure fell through to
cooldown-and-retry against a credential that fails identically every time.

- diagnostic_suffix now always includes a non-empty stderr tail alongside
  stdout instead of only falling back to it when stdout is empty
- auth_runner::is_auth_expired + ExitKind::AuthExpired classify
  expired-auth failures distinctly from rate limits; the interactive
  retry loop now prompts for re-auth instead of rotating profiles
- cli::work::handle_auth_expired (split into work_auth_expiry.rs to stay
  under work.rs's frozen LOC limit) intercepts before classify_and_cooldown,
  fails the job immediately (fatal: true, no retry-budget burn), applies
  an idempotent auth-expired label, logs the alert to both stderr and the
  job's own log file, and reuses notify_human_gate for immediate alerting
- work_item_pipeline's sdd_loop map_err sites short-circuit their own
  RetryPolicy via StepResult::Failed instead of a generic Err

Agentflare-Agent: claude-code
Agentflare-Branch: task/173-implement-detect-and-surface-agent-auth
Agentflare-Item: 173
Agentflare-Session: d168de95-65a5-4e8c-b013-83e56df9cc97

Co-authored-by: shiva <shiva@gosysinfo.tech>

* ## Summary (#667)

Implemented identity-scoped hook state for item #220:

- Added `optimize::runtime::scoped_session_key(agent, session_id)` → `"{agent}:{session_id}"`.
- `hook::pre_tool_use` and `hook::prompt_submit` now key `RuntimeState::sessions` and `staleness_checked_sessions` by this scoped key (using the already-normalized `agent` param each already received) instead of the bare session id.
- `hook_completion_gate::post_tool_use` uses the same scoped key for its `sessions` lookups and for `invalidate_verification`/`invalidate_review`.
- `hook::post_tool_failure`'s `nudge_pace` key is now `vent-nudge:{agent}:{topic_key}` instead of `vent-nudge:{topic_key}`.
- Audited the rest of the hook path: `hook_redirect.rs` has no session-keyed state, and `coaching/store.rs`'s nudge_pace keys are rule-id-based, not session-scoped, so out of scope per the task.

Single-agent behavior is unchanged since the scoped key is just `agent:session_id`, and `prune_stale_sessions` naturally prunes stale scoped entries the same way it always did.

**Tests:** `cargo test hook` → 117 passed. `cargo test optimize` → 97 passed, 1 pre-existing unrelated failure (`mcp_prompts::tests::optimize_review_returns_full_skill_body`, a skill-body text assertion in `mcp_prompts.rs` unrelated to hook state) — confirmed by stashing my changes and re-running against unmodified HEAD, same failure. Added `scoped_session_key_differs_by_agent_for_same_session_id` regression test.

**Concern:** this environment's `cargo` (via the configured `sccache` rustc-wrapper + this worktree's on-disk `target/`) fails all builds with a spurious "Read-only file system" error on writing `.d` dep-info files — unrelated to this change, reproducible on a clean build with no edits. I worked around it by building/testing with `--target-dir /tmp/... --config 'build.rustc-wrapper=""'`. Worth flagging separately since it'll block any `cargo build`/`cargo test` in this worktree until fixed.

Agentflare-Agent: claude-code_2-1-268_agent
Agentflare-Branch: task/220-borrow-notis-identity-scoped-hook-state
Agentflare-Item: 220-borrow-notis-identity-scoped-hook-state

Co-authored-by: shiva <shiva@gosysinfo.tech>

* wip(sdd-loop): task 0 checkpoint (#668)

Agentflare-Agent: claude-code_2-1-268_agent
Agentflare-Branch: task/217-borrow-notis-memory-recall-dedup-cache
Agentflare-Item: 217-borrow-notis-memory-recall-dedup-cache

Co-authored-by: shiva <shiva@gosysinfo.tech>

* chore: item::claim() doesn't check item state — a stale queued job can silently reopen a cancelled item and re-run it (#662)

* fix(dispatcher): refuse stale queued jobs against cancelled/completed items (item #226)

A job queued (or queued-for-retry) against an item survives daemon
restarts on disk in agent_jobs with no state check of its own, and
claim() doesn't guard against reopening a cancelled/completed item
either (intentionally, since a human re-claiming via redispatch is
legitimate). That let a stale automatic retry silently reopen an
already-cancelled item and spawn a fresh session.

Extend the execution-time re-resolve in fresh_dispatch_pair to also
surface the item's current state group, and have WorkItemExecutor
refuse to dispatch (fatal, no retry) when that group is cancelled or
completed. Test moved to a separate include file to stay under the
work.rs LOC gate.

Agentflare-Agent: claude-code
Agentflare-Branch: task/226-item-claim-doesn-t-check-item-state-a-st
Agentflare-Item: 226
Agentflare-Session: 093ada26-9f05-466b-99c3-d1bc149ff840

* fix(dispatcher): shorten item #226 state-gate message to satisfy rustfmt/LOC gate

cargo fmt --check was flagging the job-failure message line as over
the 100-char width, and work.rs is already pinned at the frozen
2100-line cap, so wrapping it would have failed the LOC gate instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

Agentflare-Agent: claude-code
Agentflare-Branch: task/226-item-claim-doesn-t-check-item-state-a-st
Agentflare-Item: 226
Agentflare-Session: 7bda56eb-8cf5-4c3f-ba3e-b060851a47ec

---------

Co-authored-by: shiva <shiva@gosysinfo.tech>

---------

Co-authored-by: shiva <shiva@gosysinfo.tech>
getappz added a commit that referenced this pull request Sep 12, 2026
* wip(sdd-loop): task 0 checkpoint

Agentflare-Agent: claude-code_2-1-268_agent
Agentflare-Branch: task/218-borrow-notis-pre-handoff-secret-scan
Agentflare-Item: 218-borrow-notis-pre-handoff-secret-scan

* wip(sdd-loop): task 0 checkpoint

Agentflare-Agent: claude-code_2-1-268_agent
Agentflare-Branch: task/218-borrow-notis-pre-handoff-secret-scan
Agentflare-Item: 218-borrow-notis-pre-handoff-secret-scan

* chore: item::claim() doesn't check item state — a stale queued job can silently reopen a cancelled item and re-run it (#662)

* fix(dispatcher): refuse stale queued jobs against cancelled/completed items (item #226)

A job queued (or queued-for-retry) against an item survives daemon
restarts on disk in agent_jobs with no state check of its own, and
claim() doesn't guard against reopening a cancelled/completed item
either (intentionally, since a human re-claiming via redispatch is
legitimate). That let a stale automatic retry silently reopen an
already-cancelled item and spawn a fresh session.

Extend the execution-time re-resolve in fresh_dispatch_pair to also
surface the item's current state group, and have WorkItemExecutor
refuse to dispatch (fatal, no retry) when that group is cancelled or
completed. Test moved to a separate include file to stay under the
work.rs LOC gate.

Agentflare-Agent: claude-code
Agentflare-Branch: task/226-item-claim-doesn-t-check-item-state-a-st
Agentflare-Item: 226
Agentflare-Session: 093ada26-9f05-466b-99c3-d1bc149ff840

* fix(dispatcher): shorten item #226 state-gate message to satisfy rustfmt/LOC gate

cargo fmt --check was flagging the job-failure message line as over
the 100-char width, and work.rs is already pinned at the frozen
2100-line cap, so wrapping it would have failed the LOC gate instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

Agentflare-Agent: claude-code
Agentflare-Branch: task/226-item-claim-doesn-t-check-item-state-a-st
Agentflare-Item: 226
Agentflare-Session: 7bda56eb-8cf5-4c3f-ba3e-b060851a47ec

---------

Co-authored-by: shiva <shiva@gosysinfo.tech>

* ci: Workflow-level failure discards the real per-step error, so rate-limit cooldown never fires for autonomous dispatch (#664)

* Both call sites (the two identified in the bug report as the root cause) are fixed, and there are no other callers of `finish_workflow_failed` left unpatched.

Summary of verification:
- Both `finish_workflow_failed` call sites in `execute_workflow` now fold the failing step's `last_error` into the error message, exactly as prescribed.
- `crates/flare-workflow` full test suite passes (I reran it, including the new `workflow_level_error_preserves_the_failed_steps_real_reason` regression test).
- The main `agentflare` binary compiles and its 3 `classify_and_cooldown` tests pass (I ran this myself — the implementer's own session ended without ever confirming this, having only started it as a background task and then stopping without waiting for the result, which is exactly the kind of unverified completion this process asks reviewers to catch).
- Fallback behavior (`state_store.load(...).ok()`) is safe if the store read fails — degrades to the generic message rather than panicking.
- No other `finish_workflow_failed` call sites were missed.

REVIEW_APPROVED

Agentflare-Agent: claude-code_2-1-268_agent
Agentflare-Branch: task/229-workflow-level-failure-discards-the-real
Agentflare-Item: 229-workflow-level-failure-discards-the-real

* wip(sdd-loop): task 0 checkpoint (#665)

Agentflare-Agent: claude-code_2-1-268_agent
Agentflare-Branch: task/219-borrow-notis-handoff-recursion-guard
Agentflare-Item: 219-borrow-notis-handoff-recursion-guard

Co-authored-by: shiva <shiva@gosysinfo.tech>

* fix(auth): detect and surface expired agent auth instead of silent retries (#666)

Root-cause of item #164's 15h incident: diagnostic_suffix preferred stdout
over stderr, discarding real CLI error text; the only failure classifier
was rate-limiting, so an expired-auth failure fell through to
cooldown-and-retry against a credential that fails identically every time.

- diagnostic_suffix now always includes a non-empty stderr tail alongside
  stdout instead of only falling back to it when stdout is empty
- auth_runner::is_auth_expired + ExitKind::AuthExpired classify
  expired-auth failures distinctly from rate limits; the interactive
  retry loop now prompts for re-auth instead of rotating profiles
- cli::work::handle_auth_expired (split into work_auth_expiry.rs to stay
  under work.rs's frozen LOC limit) intercepts before classify_and_cooldown,
  fails the job immediately (fatal: true, no retry-budget burn), applies
  an idempotent auth-expired label, logs the alert to both stderr and the
  job's own log file, and reuses notify_human_gate for immediate alerting
- work_item_pipeline's sdd_loop map_err sites short-circuit their own
  RetryPolicy via StepResult::Failed instead of a generic Err

Agentflare-Agent: claude-code
Agentflare-Branch: task/173-implement-detect-and-surface-agent-auth
Agentflare-Item: 173
Agentflare-Session: d168de95-65a5-4e8c-b013-83e56df9cc97

Co-authored-by: shiva <shiva@gosysinfo.tech>

* ## Summary (#667)

Implemented identity-scoped hook state for item #220:

- Added `optimize::runtime::scoped_session_key(agent, session_id)` → `"{agent}:{session_id}"`.
- `hook::pre_tool_use` and `hook::prompt_submit` now key `RuntimeState::sessions` and `staleness_checked_sessions` by this scoped key (using the already-normalized `agent` param each already received) instead of the bare session id.
- `hook_completion_gate::post_tool_use` uses the same scoped key for its `sessions` lookups and for `invalidate_verification`/`invalidate_review`.
- `hook::post_tool_failure`'s `nudge_pace` key is now `vent-nudge:{agent}:{topic_key}` instead of `vent-nudge:{topic_key}`.
- Audited the rest of the hook path: `hook_redirect.rs` has no session-keyed state, and `coaching/store.rs`'s nudge_pace keys are rule-id-based, not session-scoped, so out of scope per the task.

Single-agent behavior is unchanged since the scoped key is just `agent:session_id`, and `prune_stale_sessions` naturally prunes stale scoped entries the same way it always did.

**Tests:** `cargo test hook` → 117 passed. `cargo test optimize` → 97 passed, 1 pre-existing unrelated failure (`mcp_prompts::tests::optimize_review_returns_full_skill_body`, a skill-body text assertion in `mcp_prompts.rs` unrelated to hook state) — confirmed by stashing my changes and re-running against unmodified HEAD, same failure. Added `scoped_session_key_differs_by_agent_for_same_session_id` regression test.

**Concern:** this environment's `cargo` (via the configured `sccache` rustc-wrapper + this worktree's on-disk `target/`) fails all builds with a spurious "Read-only file system" error on writing `.d` dep-info files — unrelated to this change, reproducible on a clean build with no edits. I worked around it by building/testing with `--target-dir /tmp/... --config 'build.rustc-wrapper=""'`. Worth flagging separately since it'll block any `cargo build`/`cargo test` in this worktree until fixed.

Agentflare-Agent: claude-code_2-1-268_agent
Agentflare-Branch: task/220-borrow-notis-identity-scoped-hook-state
Agentflare-Item: 220-borrow-notis-identity-scoped-hook-state

Co-authored-by: shiva <shiva@gosysinfo.tech>

* wip(sdd-loop): task 0 checkpoint (#668)

Agentflare-Agent: claude-code_2-1-268_agent
Agentflare-Branch: task/217-borrow-notis-memory-recall-dedup-cache
Agentflare-Item: 217-borrow-notis-memory-recall-dedup-cache

Co-authored-by: shiva <shiva@gosysinfo.tech>

* chore: item::claim() doesn't check item state — a stale queued job can silently reopen a cancelled item and re-run it (#662)

* fix(dispatcher): refuse stale queued jobs against cancelled/completed items (item #226)

A job queued (or queued-for-retry) against an item survives daemon
restarts on disk in agent_jobs with no state check of its own, and
claim() doesn't guard against reopening a cancelled/completed item
either (intentionally, since a human re-claiming via redispatch is
legitimate). That let a stale automatic retry silently reopen an
already-cancelled item and spawn a fresh session.

Extend the execution-time re-resolve in fresh_dispatch_pair to also
surface the item's current state group, and have WorkItemExecutor
refuse to dispatch (fatal, no retry) when that group is cancelled or
completed. Test moved to a separate include file to stay under the
work.rs LOC gate.

Agentflare-Agent: claude-code
Agentflare-Branch: task/226-item-claim-doesn-t-check-item-state-a-st
Agentflare-Item: 226
Agentflare-Session: 093ada26-9f05-466b-99c3-d1bc149ff840

* fix(dispatcher): shorten item #226 state-gate message to satisfy rustfmt/LOC gate

cargo fmt --check was flagging the job-failure message line as over
the 100-char width, and work.rs is already pinned at the frozen
2100-line cap, so wrapping it would have failed the LOC gate instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

Agentflare-Agent: claude-code
Agentflare-Branch: task/226-item-claim-doesn-t-check-item-state-a-st
Agentflare-Item: 226
Agentflare-Session: 7bda56eb-8cf5-4c3f-ba3e-b060851a47ec

---------

Co-authored-by: shiva <shiva@gosysinfo.tech>

---------

Co-authored-by: shiva <shiva@gosysinfo.tech>

---------

Co-authored-by: shiva <shiva@gosysinfo.tech>
getappz added a commit that referenced this pull request Sep 16, 2026
…ded then removed the diagnostic probe test), so only the real fix remains. (#693)

## Status

**Root cause, found by live reproduction** (not guesswork): I ran the *actual* production dispatch path — `agentflare_jobs::sandbox::wrap()` building the real `bwrap` argv, the real `cursor-agent` binary, the real review-only prompt text — in this sandbox. `cursor-agent` printed its `system`/`init` message, echoed the prompt, then died non-zero with **zero assistant turns**, stderr: `ActionRequiredError: You've hit your usage limit ... set a Spend Limit to continue`. That's an exact match for the vent's symptom.

This means problem #1 isn't actually "review-only prompt shape breaks cursor-agent" — it's a plain account/model usage-limit lockout that happens to have hit on review-only-routed items. I traced the escalation path end-to-end (`HeadlessOutcome::Failed` → workflow `last_error` → `"Workflow failed due to step dependency failure: ..."` → `classify_and_cooldown` → `auth_runner::is_rate_limited` → per-agent cooldown → `dispatch_failure_ceiling`'s consecutive-failure cap in `dashboard/orphan_reconcile.rs`) and confirmed all of it is already wired up in this codebase (problem #2's infrastructure already exists, likely from later items #164/#173/#506). The one real gap: `is_rate_limited`'s pattern list didn't cover cursor-agent's own wording standalone (only "usage limit" happened to match by luck), and there was no test locking in the specific "step dependency failure" wrapper (a different message shape than the one existing test covers).

**Changes:**
- `src/auth_runner.rs`: added `"spend limit"` to `RATE_LIMIT_PATTERNS`, plus a test with the exact reproduced cursor-agent error text.
- `src/cli/work.rs`: added a regression test proving `classify_and_cooldown` correctly cools down `cursor` when the real usage-limit error arrives wrapped in the `"Workflow failed due to step dependency failure: ..."` message (previously only the `"One or more steps failed: ..."` wrapper had coverage).

**Verified:** `cargo fmt --check` clean; `cargo clippy --workspace --all-targets --all-features -- -D warnings -A unsafe_code -A clippy::pedantic` (CI's exact flags) clean; 9/9 `auth_runner` tests, 80/80 `cli::work` tests, 7/7 `agentflare-jobs::sandbox` tests pass.

**Concern:** I did not find or fix a code defect causing the *silent infinite loop* itself — that machinery looks correctly implemented already. If items are still observed looping past the cap in production, the gap is likely somewhere I didn't trace (e.g., a dispatch path that bypasses `agentflare_jobs::Queue`), and would need a fresh incident log to pin down.

Agentflare-Branch: task/240-vent-cursor-agent-crashes-exits-non-zero
Agentflare-Item: 240

Co-authored-by: shiva <shiva@gosysinfo.tech>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

tech-debt Internal refactoring / cleanup, no user-facing feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Disable cargo publish and binstall publish

1 participant