Skip to content

fix: isolate PR CI notification polling and preserve configured credentials - #221

Merged
mindfn merged 57 commits into
develop_basefrom
feat/F117-1354-message-delivery-lifecycle
Oct 10, 2026
Merged

mindfn merged 57 commits into
develop_basefrom
feat/F117-1354-message-delivery-lifecycle

Conversation

@mindfn

@mindfn mindfn commented Oct 10, 2026

Copy link
Copy Markdown
Owner

What / Why

CI notification polling previously waited for all tracked PRs and their optional failure diagnostics in one admission batch. One unrelated slow failure could exhaust the 30-second batch deadline and prevent an already-read passing PR from reaching its collector.

Batch admission now reads basic CI facts once. Failure diagnostics and complete reads for truncated context lists run in each PR's own work item, with its own deadline and AbortSignal. A slow item cannot discard another PR's known result. Unknown/cancelled status remains unknown; repeated polling retains the existing generation and wake idempotency.

All three query phases resolve the existing configured GitHub credential when called. The index → schedule factory → CI spec wiring preserves dynamic token changes and existing CLI-auth behavior, without changing environment or runtime configuration.

Review and validation

Published HEAD b58021f03c359760213adf6b517ca1746d11ad2d, tree 51a1bcd5e600c29feb7dde2cbda27b9ea39322c6. Astra independently approved implementation 4f2b5644e51e3d5c5d5050e23e8f7efeffec38bb at this exact complete tree, source thread_msr51149hym0i79f#0001791614056747-000447-75bf5d69. The earlier d867 changes_requested remains recorded; its credential finding is closed by the successor.

  • Author: failing batch-isolation and credential fixtures retained; final 10-file targeted API checks 146/146; API type check, formatting and diff checks passed.
  • Independent: 10 files 146/146; the two credential counterexamples passed after adapting only their dependency injection to the new resolver, with assertions unchanged. Slow unrelated PR, dynamic credentials, per-item cancellation, single batch per tick and exact one Message + Queue wake are covered.
  • No real-provider or live-runtime validation, full gate or completed operator soak is claimed.

Isolation evidence, credential evidence.

Publication and acceptance

Fork #220 was merged as eec83065ad; its tree is identical to previously published 7b78bfca. The final ancestry-only merge includes that accepted baseline while preserving the approved complete tree byte-for-byte. This fork increment contains only the two CI notification commits and their evidence, with no replay of #220 changes.

Fresh published-HEAD remote CI is pending; the previous 7b78 green checks are not evidence for this new HEAD. Upstream zts212653#1398 remains Draft pending operator acceptance/soak and maintainer review. Operator owns runtime update and restart. Existing tracking is preserved; no tracking reset is used to conceal the collector defect. No runtime/config/data mutation or self-merge.

mindfn and others added 30 commits September 21, 2026 18:53
Every connector input used to reach the user through a two-phase shape: append
a Message, then separately enqueue its Queue row. Nothing made the pair atomic,
so a crash or a rejection between the halves left a message nobody was asked to
look at, or a queued row with no message behind it.

This registers the target contract before any producer moves onto it: one atomic
Message+Queue admission per input, the closed set of producers that must migrate,
and the replay cutover for rows written under the old shape. Registering the set
up front is what makes Phase I closeable -- the alternative is discovering
producer #7 by grep after declaring victory.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Connector inputs, scheduled wakes and hold wakes, and the manual eval trigger and
CI wake all now hand over an envelope to a single admission seam instead of
driving the append and the enqueue themselves. The separate trigger seam stops
being a second way in.

Two truthfulness fixes belong with this move. Owner provenance now fails closed
rather than inheriting strict from whatever context happened to be around -- an
unproven owner must not be silently upgraded. And a manual trigger now reports
what its admission actually did, instead of reporting success for work that was
refused.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Private input picked its winner from the Queue row, so the decision died with the
row and a retry could reach a different answer. The winner is now bound to the
admission receipt, and the notice commits together with the work rather than as a
separate best-effort write.

Also here: an external input keeps the person as its actor, not the room it
arrived in; the message index moves into its own module so the queue ledger is no
longer two concerns in one file; and the delivery wiring is expressed so the
compiler owns it -- that wiring is exactly what the migration kept getting wrong
by hand, and a type error is cheaper than a lost message.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…d set

Conflict-check, limb transcripts, github-wait and the re-eval carrier each move to
a single admission, one producer at a time, with the producer registry updated as
each is taken. Working against a registered set is the point: each commit closes a
named item rather than whatever grep turned up that day.

The recurring defect across all four was the same -- a second admission that
nobody had noticed was there, or a conflict labelled at a site that never looked.
Two test fixes belong to that: one suite was exercising a trigger production never
wired, and conflict-check's AC-C1 was restored by splitting authorization from
announcement, which is what made the duplicate admission visible in the first
place.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…sent

The wait outbox decided whether to publish after it had already started sending,
so a suppression could not actually suppress. The decision now happens at a claim
taken before any send.

The claim is deliberately kept out of the delivery enum. Encoding it there made a
rollback unable to express 'claimed but not delivered', which stranded the row in
a state no path could clear.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…e trigger chain

The managed wake is the last registered producer. It is admitted once, with its
lease checked before anything is written, so a superseded generation cannot write
at all. Three defects found by cross-individual review are fixed with it: legacy
adoption had lost its lease fence; a post-commit notification could un-admit a
commit that had already landed; and the drain was sequenced behind a UI broadcast,
so a failing socket fan-out left a durable wake that nothing asked anyone to look
at.

With every producer migrated, ConnectorInvokeTrigger has no producers left, and
the whole chain is deleted -- zero references under src/. The two-phase 'append
then enqueue' shape is gone from every production path, which closes Phase I.

Finally, connector framing is preserved on envelopes delivered through the Queue.
Without it the envelope arrives but renders as plain text: the hold-ball card, its
run state and its cancel control all disappear.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…l-closed guard

Category: accepted review finding "Reject coerced lifecycle response statuses", plus two
sibling sites the review did not reach. All three are new in this PR.

`[...].includes(String(candidate.x))` reads as a fail-closed literal check and is not one.
`String(['completed'])` is `'completed'`, and any object whose `toString` returns a literal
passes too, so a value that is not a string walks through a guard whose entire job is to
reject it. These guards sit on recovered Redis rows and websocket frames —
`RedisMessageStore`, `redis-message-parsers` and `useSocket` all gate on the shared one — so
the smuggled value lands in a field whose contract is a string literal, and downstream
matching silently stops working: it is neither `processing` nor a valid terminal, so
projections can be suppressed and a terminal commit can conflict permanently.

The fix is to compare the raw value, expressed once as `isOneOf` in the shared module rather
than repaired inline at each call, so the next literal check cannot reintroduce the coercion
by habit.

Three sites, found by auditing the pattern across the tree instead of patching only the one
that was reported:

- `message-lifecycle.ts` response `status` — the reported instance.
- `message-lifecycle.ts` delivery-failure `reason` — same function, one branch away.
- `QueueLedgerValidation.assertQueueExecution` — the one that actually matters most: it is a
  throwing gate, and the coerced field is `ownerAuthProvenance`. An array was accepted as
  proven owner authorization. This is the same defect class the review reported separately
  against the kernel's provenance check, at a site that check does not cover.

Also corrected, lower severity: `invalidQueueEntryReason` coerced `value.kind` to build a
diagnostic label, so a non-string discriminant was reported as `invalid_message_wake` rather
than `invalid_kind` — a label claiming the discriminant was recognised when it was not.

Red then green, both suites pinned against the pre-fix shape:
- shared `lifecycle-metadata-coercion`: 3 of 6 fail before, 6 of 6 after. Registered in
  `vitest.config.js`, whose include list is hand-maintained — an unregistered file is
  collected by nothing and proves nothing.
- api `queue-ledger-provenance-coercion`: 2 of 4 fail before, 4 of 4 after.

Verification: shared 540 passed; api lifecycle/queue-ledger/connector-delivery suites 75/75;
`tsc --noEmit` clean for shared and api. Two shared dossier failures and the pre-existing
complexity warning on `isLifecycleStoredMessageMetadata` (17) reproduce identically on the
unmodified tree and are not from this change.

Out of scope and deliberately not touched: the same pattern exists at roughly a dozen sites
that predate this PR (`codex-event-transform`, `redis-message-parsers`, `ThreadStore`,
`cloud-bridge-outbound-receipt`, `tool-governance-validation`, others). Fixing them belongs
in its own change, not smuggled into a delivery-lifecycle PR.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…umer guess

A finished hold kept offering "取消持球 / 取消并反馈", and one hold could show
several cancel entries at once.

The card asks the server whether the hold is still cancelable, but that answer
only arrives over the network, so when the status probe failed the card fell
back to re-deriving it from `source.meta.phase` — and that copy was wrong. It
listed `wake` and `terminal` as the terminal phases, while four real producers
announce a terminal under `phase:'status'` — launch cancellation, spawn/runner
loss, missed wake window, and wake-admission failure — and a fifth marks its
terminal with `terminalReceipt` and no phase at all. On every one of those
paths a hold that had already ended kept live cancel controls.

Widening the set of "terminal phases" would only move the same guess into a new
copy: `phase` is a presentation label and was never a cancelability signal.
Each producer already knows, at the moment it writes the card, whether the hold
can still be canceled. It states that now, and the consumer stops deriving it.
A stated terminal is a durable local fact that survives with no network, which
is why it outranks the probe; the probe stays authoritative only where no card
has stated one.

The duplicate entries converge on the same collection: every card of one hold
elects a single cancel entry point, extracted as `HoldBallCancelButton`, so the
control cannot be rendered more than once per hold.

Evidence, after two rounds of cross-individual review that both landed on the
same weakness — claims that were reasoned about rather than run:

- The producer contract test was inert. Written as `test/*.test.ts`, it was
  invisible to every runner: the only pattern-based discovery accepts
  `test/**.test.js`. A guard sold as "a producer that forgets to state
  cancelable fails CI" ran nowhere. It is plain JS now and is in the shard plan.
- Stamping `cancelable` broke three exact-shape assertions on `source.meta`.
  Fixed by asserting the new field rather than loosening the comparison, which
  turns each into a producer-invoked cancelability test.
- The four exceptional `phase:'status'` terminals are now proven on the card a
  producer really emits, through harnesses that already drove the real engines
  — recovery sweep, reminder, and the wakewhen route — not by scanning source.
- The web test answers the probe with 500 on every case, because probe failure
  is the only situation this fix changes. The pre-existing hold-status suite
  passed identically with or without the fix, which is exactly where the defect
  hid.

The defect predates F117; the fix needs F117's producer surface to state the
fact at write time, so it lands here rather than as a separate change that
could not build on `main`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
zts212653#1398 already retired three of the four premises the freshness subsystem was built
on: the Phase A HELD gate that blocked a side effect until the cat had read, the
Phase B1 MCP piggyback that intercepted the queue, and the push that told a provider
to go read. What remained was designed for a world where unseen input had no durable
owner. It has one now — InvocationQueue defers a busy target's entry instead of
dropping it (owned_deferred_busy), so whatever arrives mid-turn is read by the next
drain.

This removes what that left standing. Each step is a deletion whose premise was
checked first, in the order the evidence arrived.

ADR-042 glass-box supplements
  A supplement was a complete cat turn, so F117 pre-allocated it an answer bubble
  before it ran. Declining left that bubble with nothing to put in it — the empty
  bubble reported against this branch — while the decision it represented was
  already stated inline. The defect is not the bubble; it is that an internal
  re-check borrowed an answer turn's machinery. Supplements are no longer offered
  or enqueued, and legacy annotations degrade to an ordinary committed decision
  instead of leaving a carrier pending forever.

Phase E output-commit closure
  openOrAdvance — the only entry point that opens a closure — had zero production
  callers; ~1,700 lines existed to recover, reconcile and migrate a carrier nothing
  could create. Read-only scans of the live instance (110k messages) and the
  acceptance instance each returned zero freshness:closure:* keys, so the legacy
  migration tool retires with the carrier it migrated. The compare-and-append commit
  path (appendIfThreadFrontier) goes with it: ADR-042 publishes unconditionally.

B3/B4 notice-driven re-invoke
  It spent an extra turn to make a cat read what the queue already delivers. The
  terminal hook still wrote metadata.freshnessReinvoke after its reader was removed.

Phase D output-commit scan
  It ran once per answer turn and rewrote extra.freshness.kind to 'fresh' or
  'freshness_unknown'. Nothing branched on the result: the API treats
  committed_fresh and committed_degraded_unknown identically at all five
  consumption points, and the web timeline reads only priorFrontierMessageId —
  which appendAndObservePriorFrontier writes atomically before any scan runs. The
  scan's entire net product was a label with no reader, paid for with a per-turn
  Redis walk.

Kept, with the reason it survives
  - The frontier annotation: extra.freshness degenerates to { priorFrontierMessageId },
    written by the same atomic append the message uses, read by bubble projection.
    Parsers ignore every retired verdict shape and keep only the frontier.
  - Provider-native freshness. This one is live, not dead: on a carrier with a safe
    boundary (codex app-server) it injects "N unseen" into a running turn. Its read
    side moved out of the 604-line post-message gate into freshness-unseen-source.ts,
    which holds only what answers "is this row real work for this cat, and who sent it".
  - The eval:freshness domain, decoupled from the deleted planes. Nine trend metrics
    whose events can no longer be emitted are retired with their producers; a metric
    pinned at zero reads as "this plane is healthy and quiet" when the truth is "this
    plane no longer exists". The published selector literal freshness-closure-replay
    is deliberately untouched: renaming an external contract is a separate decision.

Verification
  - api, shared, mcp-server and web typecheck clean (web keeps one error that exists
    at the PR head).
  - 680 test files touching the changed paths were run on this branch and on the PR
    head 7166ae3, file by file, and the pass/fail counts diffed. Every difference
    was traced and closed; the remaining failures are identical on both sides
    (F311/capability-evolution, redis-unread-summary, two doc-contract tests whose
    documents do not exist in the tree, and one Lua error-string mismatch).
  - Web unit suite: 7255 pass, 5 fail, all five identical at the PR head.

  - Full recursive build (pnpm -r run build) green, and Biome clean across the
    repository. Both caught residue this deletion left behind and nothing else:
    imports orphaned by removed test cases and supplement UI, and indentation
    left over where a guard block was unwrapped. Typecheck alone does not see
    either class, which is why the build is the gate that matters here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Why: queued input was published into History before its response receiver and target retirement existed, while Codex app-server deltas were discarded and several UI surfaces derived independent liveness states. Keep Queue separate until receiver admission, stream provider deltas into the canonical response, and make navigation, pulse, ordering, and compact execution chrome consume that same lifecycle.

[砚砚/gpt-5.6-sol🐾]
Why: Fork dogfood exposed that presentation order was maintained independently by many store writers, so hydration, streaming, projection, and background updates could disagree. Move ordering to one canonical read-side comparator, keep storage cursors explicit, and preserve the user scroll anchor when that view changes.

The receiver could be written before its queued source was published, while publication recomputed a later wall-clock time and made the source appear after the response. Carry the durable Queue claim time through admission, retaining the monotonic enqueue floor. Keep response startedAt and storage cursors factual; bound only its presentation time after the latest admitted input, including inputs appended to an active run. A terminal response normally freezes at completedAt, but the causal floor wins if a later input clock overtakes it.

Why (viewport follow-up): Re-sorting on every streamed chunk repeatedly moved concurrent processing cards and interrupted reading. Keep the canonical comparator unchanged; stream content in place, then commit changed card positions from a fresh snapshot in serial one-second rounds. Derive dirty rows by immutable message identity rather than writer flags, let display and scroll restoration share one viewport order, and anchor the visible paragraph or an explicitly expanded card before layout changes. Preserve immediate admission, storage pagination, and the existing lifecycle ordering tests.

Upgrade the Claude Agent SDK carrier from 0.3.267 to 0.3.280. The SDK integration is introduced by this branch, so its version belongs in this PR. Peer requirements and the existing zod 3 resolution are unchanged; the API type-check is clean. The claude-agent-service baseline has the same 29 live-config lookup failures on both SDK versions. Co-creator dogfood later confirmed opus 5.5 replies through the installed 0.3.280 SDK.

[砚砚/gpt-6-sol🐾]

[布偶猫·宪宪/claude-opus-5-5🐾]

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Why: reconcile the existing public A2A candidate with main while retaining durable Queue, exact source/target fences and one canonical response result. Consume the verified local integration source cut without making fork integration history a public ancestor. UI and contract commits follow in this same unpublished candidate; gates bind the completed cut, not this intermediate tree.
Why: complete the original RFC result ownership on active/background/history surfaces, remove read-stage and recovery notices, and fold timeout/CLI diagnostics into the original response. Preserve real user actions and callback/late-socket identity fences; validate the completed public cut in this same checkout.
Why: publish the single Queue/response responsibility model and its affected consumers with the completed candidate. This implements the existing RFC, including exact failed-response wake and cancellation, rather than inventing a read stage or a new notification protocol. Operator experience, fork soak and maintainer review remain pending.
Why: the exact public candidate production build exposed seven unused bindings left after retiring read/pause/session notice presentation. Remove the unused contract parameters and imports, migrate their existing callers and fixtures, and keep ESLint enabled. Focused lint and 55 consumer tests pass; the original failed production build remains in checkpoint-6.
Why: Partial preserved readonly modifiers from the capability constant, so deleting guidance made the full Web type gate fail. Construct the absent-guidance input directly while retaining the same fail-closed assertion. Full Web types, the two fixture tests and the real response component browser check now pass; the prior production build remains unchanged.
Why: frontier adjacency and matching failure text cannot prove retry ownership. History and story playback now retain every canonical response; execution retries remain responsible for their own response identity. Actual history and replay regressions preserve unrelated private failures.
Why: startup or abandoned-turn settlement could clear a failed child before its authorized caller return was committed. Persist the original admission provenance on its response and reuse the normal atomic failed-response and Queue-wake transaction during recovery. Keep uncertain obligations pending, preserve authority and sibling identities, and make commit replay idempotent. Cover real Queue admission, startup failure and lost acknowledgements in memory and owned Redis.
Why: recovery treated an already committed failed response as a draft, trimming its content and synthesizing optional fields until exact terminal replay conflicted forever. Pass the complete durable terminal patch directly through the shared failed-response and caller-wake transaction. Processing responses keep their draft handling; committed bodies, rich/tool fields and metadata retain their original values and presence. Cover normal commit acknowledgement loss, empty fields and real Redis restart.
Why: exact-head GitHub Lint rejected the public snapshot because active F117 was omitted and completed F220 remained in ROADMAP. Correct those two inventory rows against the existing feature records without publishing fork coordination or changing execution code. The independent 0c2a0e8 code review remains applicable by identical code and dependency blobs.

[砚砚/gpt-6.1-sol🐾]
Why: Queue, message bodies, references and member reads must project MessageFrom rather than infer operator identity from an absent catId. Preserve sender envelopes in socket events and reply previews, share display resolution, and keep navigation from declaring custody changes from prose.
Why: a timer callback can arrive while the sampled silence is still below the configured deadline. Re-arm the remaining interval so exact Stop never fires early, while preserving the existing CPU extension cap and once-only result.
Why: grouping still inferred a human sender from absent catId while body visibility consumed MessageFrom. Use the same identity entry point and retain source metadata in the queue preview regression.
Why: late approval reads and secondary chat-cache gaps could erase published cards or hide admitted executions. Fence request order, reconcile on reconnect and terminal events, and preserve canonical sender identity in live cards.
Why: client acceptance completes delivery and retires Queue work. Optional SDK input UUID evidence updates only the original source and target, persists through reload and remains independent of Stop, results and callbacks. Unsupported clients show a static delivered indicator without claiming model reading.

Validation: Web 16/16, compiled Queue and SDK 59/59, owned Unix Redis replay and styled browser interactions pass. Full CI and operator acceptance remain separate gates.

[砚砚/gpt-6.1-sol🐾]
…vidence

Why: notification producers now admit through the durable Queue, and action carrier recovery joins exact source, response, child and parent evidence. Tests must exercise those contracts rather than bare MessageStore delivery or retired custody projections. Install Redis executables for owned isolated Linux tests without relaxing the existing network boundary.

Validation: wait lifecycle and outbox 18/18, action lease races 7/7, schedule and task consumers 74/74. Prior CI failures retained; the full public gate remains to run on this candidate.

[砚砚/gpt-6.1-sol🐾]
Why: SDK failure correlation UUIDs and synthetic API errors do not prove model consumption. Preserve consumed failed-turn lists and real main-query reply evidence while leaving Queue, Stop and completion independent. Keep absent optional delivery fields absent and construct the browser fixture immutably so current type and production gates can pass.
Why: public recovery wrappers omitted Queue and could pass lookup failures before reaching their intended dependency. Use real Queue and exact History child/parent evidence, retain scope, cancellation, expiry and parallel cases, and assert every injected fault is reached.
Why: Live admission preserves its immediate single-attempt handle. The ordinary active-writer wait loop bypassed the Live retry budget and could acquire another client after refusal. Keep ordinary member recovery while returning the existing typed Live failure without replay.
mindfn added 15 commits October 9, 2026 18:50
Why: local invocation deadlines must not disable a member in other threads,
and preflight refusal must not discard the durable target before retry.
Bind native Codex input consumption to the existing exact read receipt and
render supplement dots using the sender identity.

Validation: API build; API 138/138; failure seam 5/5; transport 37/37
plus strengthened exact cases 2/2; Web 10/10; isolated browser preview.
Web type diagnostics match exact base; runtime and provider untouched.

[砚砚/gpt-6.1-sol🐾]
Why: owner directions 051/054 require requested targets to execute through the existing lifecycle and actual client failures to reply and return to the exact predecessor. Global availability prechecks, advice and terminal observations could silently suppress cross-thread delivery.

Remove these consumers instead of introducing another advisory layer. Preserve callback run identity, causal action fences and bounded retry only for actual failures before durable input acceptance. Keep native Codex read receipts and source theme colors from the prior candidate.

Rewrite the retained failed-response recovery assertion, verify serial/parallel failures through the real response/Queue transaction, and fix partial sibling handoff backoff. Retain original reds and the prior changes_requested verdict.

Validation: API build; 206/206 targeted API tests; 2/2 no-advice invocation tests; 5/5 failure-return seam; Biome error-level and diff check. Runtime code/config/data/processes unchanged.

[砚砚/gpt-6.1-sol🐾]
Why: fork #218 landed the previous candidate under a different commit identity with the same complete tree. Include its exact develop_base merge commit so the next fork PR contains only the new follow-up, without reintroducing already accepted changes.

The published file tree must remain identical to independently approved 709caf8. No code, test, config, or runtime change is introduced by this ancestry reconciliation.

[砚砚/gpt-6.1-sol🐾]
Why: public CI retained an obsolete expectation that invocation failure globally suppresses later cross-thread sends. Keep production behavior unchanged and verify actual errors, no availability query or publication, and no failed-work replay.
Why: ordinary message consumers were already removed, leaving unused lookup, hook, assembly fields and projection attribution that falsely advertised retired behavior. Delete the dead chain and retain active article tools and historical lookup compatibility.
Why: the generic append placeholder promised capability for every active member. Reuse declared guideReply support to name eligible active members and omit the tip when no member supports it, keeping sending strategy unchanged.
Why: operator clarified the tip describes active member capabilities rather than queue strategy. Remove the preference condition without changing message admission or sending semantics.
Why: the named response already records the complete provider error. Repeating it in diagnostics banners and folded excerpts obscures the single response and duplicates the operator-visible failure. Retire response-only presentation and retain standalone failure diagnostics and persisted evidence.
Why: a successful callback source must not erase an independent final response addressed to the same member. Keep routing bound to each message source and use the existing Queue identity for deduplication, preserving callback custody evidence without replaying callback targets into final prose.
Why: fork develop_base merged PR219 with exactly the same tree as published 7c87b0f. Record that accepted baseline in ancestry so the next fork PR contains only the reviewed follow-up. The complete tree remains byte-for-byte identical to Astra-approved 2f9623f; no implementation or evidence change.
Why: public CI still expected 24 per-turn hooks in two dual-path consumers after automatic Signal article injection was retired. Keep the remaining 23 hook identities and semantic checks explicit, assert D20 contributes no trace or prompt patch, and align stale catalog comments without changing production behavior.
Why: the legacy five-second body window swallowed intentional same-text messages with different client IDs, while pre-append ID claims swallowed retries after storage failures. Retire both ordinary-send gates and reuse MessageStore idempotent persistence and existing atomic Queue admission; preserve exact carrier scopes and recover only the original stored source. Cover both callback transports, concurrent requests, cross-thread delivery and failure recovery.
Why: optional failure details for an unrelated PR exhausted the shared admission deadline and prevented already-read successful CI facts from reaching their wait owner. Keep base fact collection shared and move diagnostics/exact reads to existing per-PR cancellation and timeout boundaries; retain typed failure classification and generation idempotency.
Why: moving PR-local diagnostics out of batch admission dropped the plugin credential resolver and silently switched account/request-budget ownership. Forward the existing resolver from index through the schedule factory to all CI readers, keeping batch and per-item cancellation separate and preserving CLI auth-store defaults.
Why: fork #220 was squash-merged as eec8306 with a tree identical to published 7b78bfc. Include that accepted baseline as a parent so the next fork PR contains only the CI notification follow-up. The complete tree remains the independently approved 4f2b564 tree; no production or evidence files change.
@mindfn
mindfn merged commit 4b914e2 into develop_base Oct 10, 2026
mindfn added a commit that referenced this pull request Oct 10, 2026
Why: all current user, member, connector and persisted-notification inputs must enter the same policy snapshot and durable Queue execution path. Preserve exact A2A and whispered recipient boundaries.

Reviewed source: fd01f6fe36372a098f2a73df74008b9b6932584d. Publication retains the accepted fork #221 plugin delta. Removing precisely that delta from this tree yields the approved source tree aeba47f.
mindfn added a commit that referenced this pull request Oct 10, 2026
Why: common Queue admission owns default routing and drain notification. Legacy fixtures omitted that host wiring or modeled retired connector default selection. Preserve all original identity, persistence, hook-order and wake assertions with actual common admission.

Source 1f3a8988af9819fa3e961028f32fd8a14a3d0fde, tree a8b2d9f. Tests/evidence only; production blobs unchanged from approved fd01f6fe. Original CI reds retained; author API119/119 and failure-return5/5.

Retains accepted fork #221 plugin delta byte-for-byte.
mindfn added a commit that referenced this pull request Oct 10, 2026
Why: match the shared admission host in tests and keep process artifacts outside the product PR. Preserve develop_base baseline evidence and accepted #221 plugin changes. Source 9e3db707da88ad115d93182eb89ba105748f0583; upstream 8746848.
mindfn added a commit that referenced this pull request Oct 10, 2026
* refactor(F117): unify durable message admission and execution lifecycle

Why: pending work belongs to the canonical Queue, while accepted input is owned by its response and exact execution. Consolidate producer admission, failure returns, native input-read evidence, target-based guidance and callback message identity; retire redundant custody, availability and routing projections with their regression coverage.

* feat(web): render canonical delivery feedback and member guidance

Why: the console must project the same source, response and execution identities as the backend. Consolidate delivery/read receipts, sender colors, capability-based composer guidance, exact Stop, socket recovery and complete failed-response rendering with their consumer tests.

* docs(F117): consolidate lifecycle contracts and acceptance evidence

Why: reviewers need a single delivery contract, retirement ledger and traceable red/green acceptance record. Preserve the previously reviewed documentation and evidence without including the separately owned GitHub plugin CI polling increment.

* fix(f117): append durable producer notifications to active replies

Why: external and scheduled inputs reached durable Queue admission but busy-target progress never invoked the existing Append path. Reuse exact target/run admission so eligible notifications guide the current reply, preserve unsupported/private/stopped/owner fences and source-ID replay semantics, and shorten the operator-approved guide hint.

* refactor(f117): publish unified send admission and Queue delivery

Why: all current user, member, connector and persisted-notification inputs must enter the same policy snapshot and durable Queue execution path. Preserve exact A2A and whispered recipient boundaries.

Reviewed source: fd01f6fe36372a098f2a73df74008b9b6932584d. Publication retains the accepted fork #221 plugin delta. Removing precisely that delta from this tree yields the approved source tree aeba47f.

* test(f117): wire common admission in legacy delivery fixtures

Why: common Queue admission owns default routing and drain notification. Legacy fixtures omitted that host wiring or modeled retired connector default selection. Preserve all original identity, persistence, hook-order and wake assertions with actual common admission.

Source 1f3a8988af9819fa3e961028f32fd8a14a3d0fde, tree a8b2d9f. Tests/evidence only; production blobs unchanged from approved fd01f6fe. Original CI reds retained; author API119/119 and failure-return5/5.

Retains accepted fork #221 plugin delta byte-for-byte.

* test(f117): finish admission fixture wiring and omit process evidence

Why: match the shared admission host in tests and keep process artifacts outside the product PR. Preserve develop_base baseline evidence and accepted #221 plugin changes. Source 9e3db707da88ad115d93182eb89ba105748f0583; upstream 8746848.

* test(f117): align prose fallback and ingress assertions

Why: match current shared send behavior in formal tests without changing production, accepted fork plugin code or baseline evidence. Source c3cd2ae39e023c1600306f3af654580e462e2ed0; upstream 5fcb054.

* test(f117): verify callback common-admission ownership

Why: callback producers persist exact fan-out and notify the shared drain once; native Append orchestration belongs to Queue execution. Retain the availability suppression guard and exact target assertions. No production behavior changes.

Source: f6092d917649675d0cc336dcf3201b17b45bd858
mindfn added a commit that referenced this pull request Oct 10, 2026
Why: after #222, Redis Lua converts empty payload.requestedTargetCats arrays to objects, causing both automatic drain and manual Steer to fail validation. Restore the exact accepted #221 tree while repairing and testing the codec in the feature checkout. Persistent messages, queues, runtime configuration and processes are untouched.
mindfn added a commit that referenced this pull request Oct 10, 2026
mindfn added a commit that referenced this pull request Oct 10, 2026
…very

Why: restore the reviewed common send and drain after the #222/#223 rollback, correcting Redis empty target encoding and preserving guidance until the exact native parent dispatcher is ready. Add composed Redis and HTTP Steer regression coverage.

Source: fd09784d3f4aea51b365258251639badbab90a9e
Source-tree: 6babe29
Fork-base: c29dba7
Fork-only #221 plugin changes and pre-existing evidence retained.
Runtime acceptance and soak remain pending; no process or storage changes.
mindfn added a commit that referenced this pull request Oct 10, 2026
Why: normal sends and HTTP Steer failed after unified delivery because Redis transitions changed empty target arrays into objects, and an exact preparing parent was permanently reclassified before its dispatcher bound. Preserve the admitted targets and guidance intent, then wake the same drain on readiness.

Reviewed-source: fd09784d3f4aea51b365258251639badbab90a9e
Source-tree: 6babe29
Formal composed Redis/send/drain/HTTP Steer tests included. Native dispatcher remains a controlled fixture in these tests; runtime acceptance and soak are pending. Fork-only #221 plugin changes are excluded.
mindfn added a commit that referenced this pull request Oct 11, 2026
…very (#224)

Why: restore the reviewed common send and drain after the #222/#223 rollback, correcting Redis empty target encoding and preserving guidance until the exact native parent dispatcher is ready. Add composed Redis and HTTP Steer regression coverage.

Source: fd09784d3f4aea51b365258251639badbab90a9e
Source-tree: 6babe29
Fork-base: c29dba7
Fork-only #221 plugin changes and pre-existing evidence retained.
Runtime acceptance and soak remain pending; no process or storage changes.
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