Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .agents/pm/features/pm-github-webhook-inbox.toon
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
id: pm-github-webhook-inbox
title: Reconcile authenticated GitHub webhooks through a durable deduplicating inbox
description: "Explicitly supplied issue webhook deliveries are signature verified before durable intake, deduplicated, and reconciled against current provider state into bounded proposals."
type: Feature
status: in_progress
priority: 2
tags[3]: changelog-unreleased,github,webhooks
created_at: "2026-10-21T20:34:29.731Z"
updated_at: "2026-10-22T11:47:29.084Z"
author: codex-agent
acceptance_criteria: Duplicate and out-of-order events do not regress lifecycle; signature failures cause zero writes; polling refresh remains a recovery route; typed SDK and CLI with compact TOON/JSON refusals and remedies; real public-tracker copy validation without git; npm and Bun CI gates pass.
comments[13]{created_at,author,text}:
"2026-10-21T20:34:36.573Z",codex-agent,"Overlap audit: existing refresh.ts polls only explicitly linked issues and owns update-only import transactions. Installed CLI MCP tool definitions transport pm commands, with no authenticated GitHub event inbox. pm-observer src/ingest.ts and export-adapters.ts ingest agent exports, not provider webhooks. No duplicate feature found by tracker search. PR #164 owns historical tracker reconciliation; its items remain untouched. Design: authenticate exact payload bytes before all writes; store minimal durable delivery hints; reconcile via current-provider refresh previews only; retain receipts and retry failures. Polling refresh remains the apply and recovery route."
"2026-10-21T20:41:00.447Z",codex-agent,"Implementation: authenticated intake stores minimal immutable delivery hints; token-owned writer locking serializes concurrent deduplication; atomically published receipts are file/directory-flushed before acknowledgment. Reconciliation coalesces selected issue numbers and uses read-only current-provider refresh previews, persisting compact outcome receipts without item changes. No receiver is installed. Local targeted suite: 7/7 passing, new webhooks.ts measured 100% statements/branches/functions/lines. No-git acceptance removes git from PATH and sets a discovery ceiling. CI now invokes explicit npm and Bun release:check at unchanged thresholds; full gates run remotely because the host is saturated."
"2026-10-21T20:43:37.315Z",codex-agent,"Behavioral revert proof: removing only signature verification from acceptGithubWebhook makes the signature-failures test exit 1 with Missing expected rejection; restoring it passes. Removing only the runRefresh number-scope predicate makes the stale-event test exit 1 because unrelated issue #2 is queried. Restored both functions. Real public-data acceptance: verified the source repository is public, copied main tracker into a non-git scratch project, made original files read-only, removed git from PATH, and hash-checked 294 original files. Measured 144 items, 5 linked issues, 10 accepted synthetic signed hints and 10 duplicates; 10 reconciled, 0 pending/retry, 5 proposals matching a fresh polling preview. All 294 original file hashes unchanged; compact JSON receipt 3274 bytes. No provider writes."
"2026-10-21T20:44:43.174Z",codex-agent,"The broader local refresh-plus-webhook linked run reached its default 120-second limit under host load after 16 passing refresh scenarios; no assertion failure was reported before termination. Narrowed the linked local acceptance to the seven webhook scenarios (including provider-state scoping and polling apply/recovery), with an explicit 300-second ceiling. Full existing-suite evidence is delegated to CI as requested."
"2026-10-21T20:45:12.776Z",codex-agent,"Local acceptance complete: pm test --run --progress passes the linked webhook command, 7 tests, zero failures/skips/TODOs; typecheck, test typecheck, lint, docstring, zero-duplication and changelog checks pass. New inbox module has exact 100/100/100/100 targeted coverage. Public-data validation and behavioral fault checks are recorded above. Implementation is handed to CI for unchanged-threshold npm/Bun release gates; no merge or release is authorized. Operational limits: local POSIX filesystem inbox, explicit adapter intake, indefinite deduplication retention, proposals must be refreshed before apply."
"2026-10-21T21:10:01.817Z",codex-agent,"Final concurrency review found that the common inbox lock spans provider reads, so slow GitHub access can block authenticated intake until its bounded lock wait expires. Separate the intake and reconciliation lock lanes: immutable atomically published hints permit concurrent intake while processors remain serialized. Add a real HTTP delayed-read regression and behavioral revert proof, then rerun CI on the new head."
"2026-10-21T21:10:54.627Z",codex-agent,"Concurrency regression: withhold the real HTTP provider response, then accept another signed delivery before releasing that response. The separate lock lanes pass; reverting only reconciliation to the shared intake lock exits 1 with inbox_unavailable after contention. Restored the fix. CI npm/Bun release gates now run in parallel jobs, preserving Node 22/26, native Bun acceptance and all existing thresholds."
"2026-10-21T21:14:01.708Z",codex-agent,"Final local result after concurrency hardening: linked pm test passes 9/9, zero failures/skips/TODOs; targeted inbox coverage remains exact 100/100/100/100. Typecheck, test typecheck and lint pass. Separate processor/intake locks keep receipt acceptance available during delayed provider reads. Refresh previews exclude durable inbox storage; reverting only that exclusion makes the opaque-storage regression fail with provider_unavailable. Repeated public-data validation on this code: 144 items, 294/294 original file hashes unchanged, 5 issues, 10 accepted hints, 10 duplicates, 10 reconciled, zero pending/retry, 5 proposals matching polling and a 3274-byte report. The previous CI run was canceled after both npm gates passed because it predates this fix; only the new head will supply final gate evidence."
"2026-10-22T11:12:36.254Z",codex-agent,"PR #165 review round: fetched all two unresolved threads with complete comments and the latest CodeRabbit review; no outside-diff findings. Merged current main before fixes. Verified age-only lock reclamation and retry-prefix starvation against the pinned SDK and implementation. Plan: require explicit recovery for expired inbox locks so live workers cannot be displaced; persist a rotating batch cursor before provider reads, including failed batches; exercise real non-git trackers and delayed HTTP reads, then record behavioral reverts and unchanged npm/Bun release gates."
"2026-10-22T11:15:04.907Z",codex-agent,"Verified both findings and self-reviewed the full PR diff. Applied the pinned SDK forceRequiredForStaleLock guard to both processor and intake locks; it prevents age-only displacement rather than implementing a heartbeat. Documented explicit crash-lock recovery. Added an atomic repository-scoped rotating cursor, advanced before provider I/O so thrown requests also yield to later hints. One directory snapshot keeps queue counts consistent during concurrent intake. Regression fixtures cover missing states, thrown HTTP failures, wrapping, corrupt cursor refusal, aged live processor contention and aged intake locks. Clean-home strict health passes; normal-home strict health detects unrelated globally installed host/extension version skew. No merge receipts are pending."
"2026-10-22T11:15:18.387Z",codex-agent,"Behavioral revert proofs (all restored): reverting only locked acquisition to forceRequiredForStaleLock=false makes node --test --test-name-pattern=\"expired live processor|expired intake\" test/webhooks.test.ts fail 2/2 with Missing expected rejection; a competing processor and intake can steal aged live locks. Reverting only batch selection in reconcileGithubWebhooks to selected.slice(0, limit) makes node --test --test-name-pattern=\"retry batches\" test/webhooks.test.ts fail 1/1: the later ready issue reconciles 0 instead of 1. Moving only cursor persistence past the provider read fails the same regression 1/1, proving thrown batches must advance. Fixed cursor regression passes 1/1. Next: complete Node and Bun gates, unchanged four 100% coverage dimensions."
"2026-10-22T11:27:36.760Z",codex-agent,"Current fixed-code acceptance: pm test pm-github-webhook-inbox --run --progress passes 12/12, zero failures/skips/cancellations/TODOs; bun test --timeout 600000 test/webhooks.test.ts passes 12/12 on Bun 1.3.5. Isolated targeted c8 reports webhooks.ts at exact 100/100/100/100. npm ci, build, test typecheck, lint, docstrings and zero-duplication pass. Clean-home full npm release gate passed privacy and is still executing existing integration scenarios under host contention without failures. Push the completed review fixes to obtain complete clean CI npm/Bun gate evidence; no merge or release. Thread PRRT_kwDOTbN4pM6vALGP fixes age-only processor lock theft, including the same intake defect. Thread PRRT_kwDOTbN4pM6vALGU fixes retry starvation, including thrown provider requests."
"2026-10-22T11:47:27.554Z",codex-agent,"Release-gate receipt for code commit 3e0dbe4a3d079f166275ee44413d7c3b3c04f35a: CI run https://github.com/unbraind/pm-github/actions/runs/39770780741 reports all four required release steps successful: npm run release:check and bun run release:check on Node 22 and 26. Downloaded completed Bun job logs independently confirm 1001/1001 tests on each Node version, zero failures/skips/cancellations/TODOs, and exact 100/100/100/100 across 17 authored modules at unchanged thresholds. Both npm jobs are performing additional native Bun acceptance after their successful complete release gates; their full logs are not yet downloadable. The redundant local clean-home full npm gate was stopped after the four CI release gates passed, with no assertion failures reported before termination; it is not counted as a passing local gate. Local linked PM acceptance and native Bun webhook acceptance both pass 12/12, and targeted inbox coverage is exact 100/100/100/100. Full PR self-review and repeated complete thread fetch found no further findings. Operational risk: crashed inbox workers now require explicitly verified stale-lock recovery; receipts must be retained. Handoff remains in_progress for orchestrator verification; no threads replied to or resolved, no merge and no release."
files[5]{path,scope}:
.github/workflows/ci.yml,project
index.ts,project
refresh.ts,project
test/webhooks.test.ts,project
webhooks.ts,project
tests[1]{command,scope,timeout_seconds,provenance{author,created_at,source_kind,source_ref}}:
node --test test/webhooks.test.ts,project,300,codex-agent,"2026-10-21T20:44:40.939Z",local_mutation,feat/webhook-reconciliation-inbox
docs[2]{path,scope}:
docs/webhook-inbox.md,project
README.md,project
body: ""
Loading
Loading