Skip to content

fix(kanban): gate dependencies on exact parent results - #97151

Open
MisterNunm wants to merge 2 commits into
NousResearch:mainfrom
MisterNunm:MisterNunm/hermes-qa-result-gate
Open

MisterNunm wants to merge 2 commits into
NousResearch:mainfrom
MisterNunm:MisterNunm/hermes-qa-result-gate

Conversation

@MisterNunm

@MisterNunm MisterNunm commented Aug 28, 2026

Copy link
Copy Markdown

What does this PR do?

Kanban dependency release currently treats a terminal parent as successful even when the parent recorded a machine-readable failure result. That can release QA-gated deployment or release children after QA has completed with qa_failed.

This PR adds an opt-in, nullable edge-level required_parent_result predicate. A gated edge is satisfied only when the parent is exactly done and tasks.result exactly matches the declared value. Existing NULL edges keep their current done/archived behavior.

The predicate is explicit and generic: it does not infer approval from task titles, assignees, summaries, comments, or metadata prose. Idempotent create retries also compare the exact parent/result dependency contract and fail closed instead of silently returning a task with stale or weaker edges.

This supersedes the closed publication attempt #97141; the implementation is republished from the requested fork branch name.

Related Issue and Semantic Ownership

Related to #67132.

This overlaps with #67156 and #68850 but uses a different contract:

Proposed landing graph:

This PR does not import code from the other active PRs. Consolidation should be coordinated with their authors before landing. The current implementation also still needs to be restacked with the accepted fracture owners in #79893, #79894, #79895, #79940, and #79982 rather than establishing new long-term authority in the monoliths.

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

  • hermes_cli/kanban_db.py: add the nullable schema migration, shared dependency predicate, and enforcement across create/link/recompute/claim/reclaim/unblock/manual promotion paths.
  • hermes_cli/kanban_db.py: make idempotent create retries compare exact parent IDs and result predicates before reusing an existing task.
  • hermes_cli/kanban.py: add typed create/link CLI options.
  • tools/kanban_tools.py: expose typed create/link tool schema fields and handlers.
  • plugins/kanban/dashboard/plugin_api.py: accept the predicate and use the same blocker logic for manual/dashboard promotion.
  • tests/hermes_cli/test_kanban_required_parent_result.py: cover exact success, failure/null/case mismatch, archived gated parents, legacy compatibility, dispatcher ticks, force behavior, migration, CLI/tool surfaces, exact and conflicting idempotent retries, and post-completion result edits.
  • tests/plugins/test_kanban_dashboard_plugin.py: cover dashboard create/link persistence and manual ready rejection.
  • contributors/emails/nunm1107@hotmail.com: map the commit email to MisterNunm without rewriting history.

How to Test

  1. Run the complete Kanban regression family:

    ./scripts/run_tests.sh tests/hermes_cli/test_kanban*.py tests/tools/test_kanban_tools.py tests/plugins/test_kanban_dashboard_plugin.py -q --file-retries 0

    Verified result on current head ef4ac92a: 394 passed, 0 failed, 1 Windows-only skipped across 49 files.

  2. Run the contributor mapping tests:

    ./scripts/run_tests.sh tests/scripts/test_contributor_map.py -q --file-retries 0

    Verified result: 7 passed, 0 failed.

  3. Run Ruff on the changed Python files. Verified result: All checks passed!.

  4. Run git diff --check origin/main...HEAD. Verified clean.

The repository-wide suite was attempted but is not claimed green. A worktree-local optional-dependency environment allowed the Anthropic and ACP tests to pass, but unrelated tests then hit Linux Unix-socket path limits, desktop-environment assumptions, and live-runtime guards. Updater tests also replaced that local virtual environment during the parallel run, invalidating the remaining repository-wide receipt. The disposable environment was removed and the complete Kanban family was rerun cleanly through the canonical wrapper.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits
  • I searched for existing PRs and documented the overlap above
  • My PR contains only changes related to this fix
  • I've run pytest tests/ -q and all tests pass — the complete 49-file Kanban scope passes; the repository-wide run was not a valid green receipt for the environment reasons documented above
  • I've added tests for my changes
  • I've tested on my platform: WSL2 Ubuntu, Python 3.11 test environment

Documentation & Housekeeping

  • Relevant documentation is covered by code/tool descriptions and docstrings; no standalone guide change is required
  • cli-config.yaml.example — N/A; no configuration key was added
  • CONTRIBUTING.md / AGENTS.md — N/A; no repository workflow convention changed
  • Cross-platform impact considered: implementation uses platform-neutral Python and SQLite; Windows-only tests remain on their CI lane
  • Tool descriptions and schemas were updated for the new typed create/link fields

Screenshots / Logs

N/A — this is a database and dispatcher invariant with automated regression coverage.

@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have comp/cron Cron scheduler and job management comp/cli CLI entry point, hermes_cli/, setup wizard comp/plugins Plugin system and bundled plugins sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Aug 28, 2026

@andrexibiza andrexibiza left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed exact head 73fca308cca0c51ef9a1e36386aebcfb7988e2b4 against live main@9978706e9303dbf990d90e744b131361449d73b9 (merge base 35328345d5e3b5badc47271bdb8828e1fd2d25f4; this head is 1 commit ahead / 2 behind current main). I read the full six-file diff, the current Kanban DB/CLI/tool implementations, the dispatch/claim enforcement path, exact-head workflow state, #67132, and the live competing/predecessor implementations #67156, #68850, and superseded #97141.

The core shape is strong: the predicate is explicit rather than inferred from prose, legacy NULL edges remain backward-compatible, one shared dependency evaluator reaches recompute/manual promotion/dashboard paths, and claim_task() revalidates inside the write transaction immediately before ready -> running. That last check is particularly important; it closes stale/manual-ready state rather than trusting an earlier projection.

P1 — an idempotent create can silently discard the new gate contract

hermes_cli/kanban_db.py:create_task() still returns an existing non-archived task immediately when idempotency_key matches:

if idempotency_key:
    row = conn.execute(
        "SELECT id FROM tasks WHERE idempotency_key = ? "
        "AND status != 'archived' "
        "ORDER BY created_at DESC LIMIT 1",
        (idempotency_key,),
    ).fetchone()
    if row:
        return row["id"]

That happens before this PR validates/persists required_parent_results. So an existing child created with a legacy edge (or a different required result) can be returned as success when a retry now requests required_parent_results={qa: "ready_to_deploy"}. If the existing parent is done with qa_failed, the existing legacy edge is already satisfied and that child can remain runnable even though the retry explicitly requested the stricter contract.

This is a proof-scope mismatch at the idempotency boundary: the request says “this exact dependency contract,” but the dedup key proves only “some non-archived task with this key exists.” Please make an idempotency hit compare the safety-relevant dependency contract before returning it. Exact equality may return the existing task; a narrower/different existing contract should fail closed (or be upgraded atomically only if that is an explicit API contract). Add a regression for legacy/different gate -> same idempotency key -> stricter gate proving no child becomes claimable under the stale contract.

P1 — there are three active authorities for the same dependency-success boundary; landing needs one semantic owner

This PR is usefully different from the prior work, but it is not isolated from it:

  • peacockesq owns #67132 and the direct approval-specific implementation #67156 (task_links.gate_type, structured terminal-run approved: true, reviewer identity/ambiguity handling).
  • chahababa owns #68850, the alternative semantic-verdict implementation over the same create/link/recompute/claim/manual/dashboard boundary.
  • MisterNunm owns closed #97141 and this republished exact-result implementation #97151.

#97151's exact result predicate is complementary to #67156's approval contract; #68850 is a competing inference model. They all modify the same central dependency authority and several of the same files. Two independent columns/evaluators cannot land without declaring composition/precedence, and the inference path in #68850 should not silently coexist with this PR's explicit-contract guarantee. Please establish the merge/supersession graph and converge on one typed edge-policy evaluator, while preserving all three contributors' credit. #97141 is correctly described here as superseded publication history, not a second active implementation.

P1 landing gate — this re-grows three formal fracture targets

The behavior is worth keeping, but the current placement adds new authority directly into three tracked >2K surfaces: hermes_cli/kanban_db.py (#78632), hermes_cli/kanban.py (#79940), and tools/kanban_tools.py (#79982). The current diff itself reaches past lines ~7,000, ~2,100, and ~2,300 respectively. For kanban_db.py, the accepted decomposition already has a schema/model owner in #79893, transaction owner #79894, and claim/lock owner #79895; this PR's claim-time gate currently edits the exact lifecycle #79895 extracts.

Please preserve this semantic fix but restack it onto bounded owners rather than making the monolith the new authority again. At minimum the schema belongs with the schema owner and the claim-time enforcement must compose with the claim owner. The CLI/tool projections likewise need their #79940/#79982 fracture order called out rather than accumulating new behavior in those files.

Attribution / exact-object acceptance

The sole commit is TJKIM <nunm1107@hotmail.com> and current main has no contributors/emails/nunm1107@hotmail.com mapping. Please add the mapping to MisterNunm; no history rewrite is needed.

Exact-head hosted acceptance is also still absent: CI 33172192385, Docker 33172191821, and Nix 33172191907 are all action_required; the CI run currently contains zero jobs. The reported 388-test local receipt is useful evidence, but it is not an exact-head hosted landing receipt, and this PR has only this one commit, so the per-commit green gate is currently unmet.

One additional regression I would add while touching this: edit_completed_task_result() can mutate tasks.result after a parent is already done. Claim-time revalidation makes the obvious pre-claim case safe, but tests should pin both matching -> edited away -> held and nonmatching -> edited to match -> eligible so the fact that result is now policy-bearing does not remain implicit.

This is a good direction: explicit edge contracts + mutation-time revalidation are much stronger than reconstructing semantic success from titles or prose. Close the idempotency hole, settle the competing-policy/landing graph, restore attribution, and get the exact commit through hosted CI, and the underlying primitive is solid. 🚀

This branch has not been deployed

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

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard comp/cron Cron scheduler and job management comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants