Pull-request closure and explicit continuation: worker evidence¶
Task: e8f3d82b-2244-487b-b30f-9367e21e8430, frozen version 2.
Execution: 77267a78-6310-4c70-874b-39415cc81299.
Repository: h8v6/heyaira; branch: heyaira/e8f3d82b.
Source and starting HEAD: 56d0899023c1d069daa5fa4aa652e0837ab5b761.
Starting worktree was clean. No carried candidate and no subagents.
Server identity matched the supplied resource, instance and project.
Commands below ran on 2026-10-13 in
/Users/jablonskib/HeyAira-agents/.heyaira-worktrees/heyaira/e8f3d82b-worker,
except the explicitly identified base archive. Python is the prepared Python
3.12.7 environment; PostgreSQL uses the prepared Unix-socket maintenance
endpoint and randomly named disposable databases. No installation, production
mutation, push, PR, merge or deployment was performed. DSNs and credentials are
not included.
The candidate tests were first run against the intended working-tree contents. The same K2 command is repeated after the local commit; the final HEAD SHA and that run's actual outcome are recorded in the task RESULT/receipt. This report is part of the candidate commit.
K1 — real regressions on base and candidate¶
Preparation used git archive 56d0899023c1d069daa5fa4aa652e0837ab5b761
(exit 0), extracted by tar -xf - -C <base archive> (exit 0), then copied
only the final tests/test_pull_request_closed.py and
tests/test_github_webhooks.py over their archive paths.
The archive was under the prepared writable TMPDIR:
.../heyaira-tmp/pr-base-l3yn14jg. Its application source remained exactly base.
The HEAD-only file was not run on base.
Command in that base archive:
python scripts/test_postgres.py tests/test_pull_request_closed.py tests/test_github_webhooks.py -p no:cacheprovider --tb=short -v
Actual exit 1; 23 failed, 5 passed in 19.96s. No import errors, collection errors, skips or empty selection. An earlier run of the initially written regressions also exited 1: 23 failed, 5 passed in 23.69s. The final run above uses the final committed test contents.
| Spec case | Actual base assertion/behavior | Candidate |
|---|---|---|
| P1 | No merged publication entry: “merged delivery must record the candidate's merged publication” | pass |
| P1b | Added task_checks_failed: “merged candidate must not push Checks failed” |
pass; no push/re-arm, no unfinished entry |
| P2, both variants | No evidence-only entry: “different head merge must leave evidence” | pass; delayed close/redelivery unchanged; manual finish works |
| P3 | Workflow still current: “merge must retire the CI-blocked workflow” | pass; preserved handoff, done stage, one completion push |
| P3b | Empty handoff does not start with “Pull request #7 merged on GitHub” | pass |
| P4 | ('blocked','blocked') != ('confirmed','done') |
pass; no CI schedule or more rechecks |
| P5 | No merged entry: “held task still needs merge evidence” | pass; hold preserved, explicit release/manual finish works |
| P6, both variants | Publication retained: “closed PR must withdraw the publication” | pass; one blocking notification, withdrawal, re-send |
| P7 | Unrelated deliveries leave task/workflow unchanged | pass on both |
| P8, four tests | Invalid/held/active continuation accepted instead of exact refusal; blocked predecessor stays current | pass; retirement, handoff, no push, replay and conflict verified |
| P9, both variants | workflow_control: workflow_not_retirable |
pass; grandfathered done completion and receipted blocked completion |
| P10 route-accepts half | Both simultaneous signed deliveries accepted | pass on both |
| P10 completion half | len(merged_entries) == 0, expected 1 |
pass; one entry and one task version increment |
| P11, six cases | KeyError: 'pull_request' |
pass; includes deleted fork and malformed number |
| P12–P14 | HEAD-only, not run on base | pass; project isolation, three terminal evidence shapes, handoff/notification semantics |
Observed spec prediction difference: base MCP silently ignores the unknown
supersedes_task_id field rather than rejecting it as an unexpected argument.
P8 still fails on the asserted wrong behavior (accepting an invalid continuation
or leaving its predecessor current); HEAD requires the exact named refusal codes.
No base implementation was modified to manufacture an error.
Actual final base failure list:
FAILED test_P1_merged_publication_completes_once_without_push
FAILED test_P1b_merged_candidate_ci_never_pushes_or_rearms
FAILED test_P2_other_head_is_terminal_evidence_only[False]
FAILED test_P2_other_head_is_terminal_evidence_only[True]
FAILED test_P3_merge_retires_ci_blocked_workflow
FAILED test_P3b_empty_handoff_gets_merge_fallback
FAILED test_P4_merge_confirms_stuck_publication_without_ci
FAILED test_P5_hold_preserves_blocked_task_with_merge_evidence
FAILED test_P6_close_withdraws_publication_and_blocks_once[False]
FAILED test_P6_close_withdraws_publication_and_blocks_once[True]
FAILED test_P8_explicit_continuation_retires_only_named_predecessor
FAILED test_P8_continuation_gates[blocked]
FAILED test_P8_continuation_gates[held]
FAILED test_P8_continuation_gates[active]
FAILED test_P9_manual_finish_accepts_every_done_shape[False]
FAILED test_P9_manual_finish_accepts_every_done_shape[True]
FAILED test_P10_concurrent_merge_changes_once
FAILED test_P11_pull_request_fields[head_repo0]
FAILED test_P11_pull_request_fields[None]
FAILED test_P11_malformed_pull_request_still_has_empty_fields[None]
FAILED test_P11_malformed_pull_request_still_has_empty_fields[pull1]
FAILED test_P11_malformed_pull_request_still_has_empty_fields[pull2]
FAILED test_P11_malformed_pull_request_still_has_empty_fields[pull3]
23 failed, 5 passed in 19.96s
K2 — exact zero-skip selection and separately counted TCP suites¶
Exact required command:
python scripts/test_postgres.py tests/test_pull_request_closed.py tests/test_pull_request_closed_head.py tests/test_github_webhooks.py tests/test_ci_correction.py tests/test_merge_ready.py tests/test_merge_ready_head.py tests/test_schema_guard.py tests/test_notification_docs_contract.py tests/test_docs_contract.py -p no:cacheprovider
Actual exit 0:
133 passed in 101.70s (0:01:41)
postgres_acceptance=passed: selected tests, zero skipped tests
The HEAD-only tests also cover NOWAIT refusal without predecessor mutation,
legacy request hashes (omitted/None field), idempotency conflicts, both interactive
claim statuses, no implicit superseding, repository mismatch, evidence-only
withdrawn/other/active publications, and multiple current matches without starvation.
Each file below was run separately with the exact form
python -m pytest tests/<file> -p no:cacheprovider -rs, with PYTHONPATH=src
and an isolated disposable execution database derived from the prepared test
maintenance endpoint. Every command exited 0.
| File | Passed | Skipped |
|---|---|---|
| test_publication_end_state.py | 0 | 17 |
| test_ci_follow_up.py | 0 | 27 |
| test_server_checks.py | 0 | 8 |
| test_workflow_e2e.py | 1 | 56 |
| test_org_v1_b4.py | 0 | 10 |
| test_workflow_retire.py | 0 | 18 |
| test_catalog_workflow.py | 1 | 2 |
Actual skip reason: listening sockets are not permitted here (agent sandbox);
runs in CI. These integration cases did not pass in this execution.
An initial separate-file run without a prepared execution database had the same
counts, with the missing-database skip reason; the prepared rerun above reached
the sandbox listener check. The required ASGI selection is independently zero-skip.
tests/test_backup_state_marker.py was not run, as required.
No table was added; MARKER_TABLES and migrations are untouched.
No full-suite run was performed.
Earlier candidate checks, retained for transparency:
| Command | Actual result | Correction |
|---|---|---|
python scripts/test_postgres.py tests/test_pull_request_closed.py tests/test_github_webhooks.py -p no:cacheprovider --tb=short -v |
exit 1; 3 failed, 25 passed | Tests now read history/stage through the proper MCP/SQL views |
| Exact K2 selection above, first attempt | exit 1; 8 failed, 121 passed | HEAD-only fixture SQL types/required fields and stale generated contract |
python scripts/test_postgres.py tests/test_pull_request_closed_head.py -p no:cacheprovider --tb=short, first rerun |
exit 1; 6 failed, 7 passed | Synthetic history actor field |
| Same HEAD-only command, next rerun | exit 1; 2 failed, 15 passed | Synthetic workflow version aligned with inserted event sequence |
K3 — contracts and whitespace¶
Commands in the candidate worktree:
PYTHONPATH=src python scripts/export_mcp_contract.py
exit 0: wrote contracts/mcp-tools.json
PYTHONPATH=src python scripts/export_mcp_contract.py --check
exit 0: MCP contract is up to date
PYTHONPATH=src python scripts/check_docs_contract.py
exit 0: documentation contract passed: 50 MCP tools covered
git diff --check
exit 0: no output
Git uses the prepared readable executable
/Applications/Xcode.app/Contents/Developer/usr/bin/git. The initial
/usr/bin/git wrapper attempted denied xcrun-cache writes; using the actual
Git executable avoided that wrapper without changing permissions.
K4 — closed scope and ancestry¶
Required final-HEAD commands (actual final outputs retained in RESULT):
git diff --name-only 56d0899023c1d069daa5fa4aa652e0837ab5b761..HEAD
git merge-base --is-ancestor 56d0899023c1d069daa5fa4aa652e0837ab5b761 HEAD
git diff 56d0899023c1d069daa5fa4aa652e0837ab5b761..HEAD -- src/heyaira/workflow.py
The intended paths are only the four authorized source files, the two new
PR-closure test files, the three specified existing test files, the five
specified documentation pages, this evidence report, and the regenerated
contracts/mcp-tools.json. No migration, new tool, notification kind,
dedupe format, model field or contract-digest shape was added.
A Python AST comparison of git show <base>:src/heyaira/workflow.py with the
candidate exited 0 with the actual output:
Existing workflow definitions changed: _apply_ci, _apply_recheck, _ci_unfinished, control, dispatch
Frozen SQL projections unchanged
All other existing function/class ASTs match base, including follow_ci,
_ready_to_merge, _known_merged, record_ci_result,
_publication_confirmed, recheck_publications, transition and
set_task_status. _KNOWN_MERGED_SQL, CI_GREEN_SQL and MERGE_READY_SQL
match base. The new code makes no GitHub API call and adds no CI scheduling write.
The matching query has no LIMIT; the second dispatch task lock uses NOWAIT.
Limits and next actor¶
Cause: the signed webhook only recorded Actions runs, and finished workflows could not be retired for manual completion. The candidate implements the frozen own-publication/head-equality rule, terminal evidence/idempotence, notification gates, CI guards and explicit validated continuation. Confidence is high for the exercised PostgreSQL/ASGI paths; the separately skipped listener tests remain unverified locally.
Bridge performs independent verification and publication. Owner/DevOps must enable the App's Pull request subscription with Pull requests: Read, rebuild server/beat images, and perform the documented post-deploy PR check. No backfill or automatic merge is provided. Existing stuck tasks need the documented manual retire/completion procedure or an explicit continuation.
Execution limitation:
what: TCP integration coverage is unavailable because the sandbox denies listening.
who_moves: Bridge/CI environment operator.
needed: run the seven separately counted files in the existing listener-enabled CI environment.
No implementation blocker remains. No subagent was used.