mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-30 21:49:18 +01:00
refactor(server): expose retryable accepted-response recovery failures
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
6e20f0cfc9
commit
c448162b96
4 files changed
+52
-7
No files matched your search
@@ -2283,3 +2283,14 @@ must remain intact. The existing external-chat baseline passed 33 selected cases
|
||||
The old action-required check on #17576 is Superagent Security Scan. Its existing
|
||||
voice-review findings and the older E2E failures remain outstanding. Work on the
|
||||
rest of the original stack continues; none of these gates are waived.
|
||||
|
||||
Slice 48's first owner-contract change now passes the same 33 real-PostgreSQL
|
||||
response cases plus server typecheck. The strict recovery entry point propagates
|
||||
operational errors; existing callers keep their logging/boolean contract. No
|
||||
response worker has been wired and no response polling is removed yet.
|
||||
|
||||
The Superagent action-required gate on #17576 was traced to review 5643793631,
|
||||
inline finding 4371283330: repeated connection/health writes reload the full live
|
||||
voice-session inventory. This is the already-recorded bounded-discovery issue,
|
||||
not a missing credential or permission. It still needs a code/test repair and
|
||||
fresh review; the gate must not be bypassed.
|
||||
@@ -107,3 +107,19 @@ The monitor-continuation and control-plane-port suites currently require embedde
|
||||
PostgreSQL directly. Qualify a validated external-test path if needed before using
|
||||
their results on this host; do not count skipped or initialization-failed suites.
|
||||
No sleep or migrated-worker behavior is established by this baseline.
|
||||
|
||||
## Initial owner-contract change
|
||||
|
||||
`recoverCommittedNativeChatResponse` now exposes the existing transaction and
|
||||
returns false for settled/ineligible/authorization-denied state, while propagating
|
||||
operational failures. The existing `repairCommittedNativeChatResponse` wrapper
|
||||
retains logging and false-on-error behavior for current callers. Authority checks,
|
||||
lock order, target materialization, and commit signaling remain in the same owner.
|
||||
The commit signal itself contains subscriber errors, so the wrapper does not hide
|
||||
a previously propagated publication error.
|
||||
|
||||
The same 33-case real-PostgreSQL selection passes after this change, with added
|
||||
assertions that the new entry point rejects under actual source-action lock
|
||||
contention and returns false for the existing authorization/binding fences. The
|
||||
server typecheck passes (`/tmp/sleep48-contract-typecheck.log`). Worker discovery,
|
||||
producer notifications, startup wiring, and periodic removal are not implemented.
|
||||
@@ -248,6 +248,7 @@ import type {
|
||||
import {
|
||||
finalizeNativeRun,
|
||||
repairCommittedNativeChatResponse,
|
||||
recoverCommittedNativeChatResponse,
|
||||
} from "../services/native-runtime/native-run-finalizer.js";
|
||||
import { NativeRunCoordinatorStore } from "../services/native-runtime/native-run-coordinator-store.js";
|
||||
import { reconcileNativeFinalizations } from "../services/native-runtime/native-finalization-reconciler.js";
|
||||
@@ -71948,6 +71949,11 @@ describeEmbeddedPostgres("chat channel control-plane integration", () => {
|
||||
})
|
||||
: context.repair(),
|
||||
).resolves.toBe(false);
|
||||
await expect(recoverCommittedNativeChatResponse(db, {
|
||||
companyId: mutation === "cross_company" ? randomUUID() : context.fixture.companyId,
|
||||
issueId: context.issue.id,
|
||||
runId: mutation === "cross_run" ? randomUUID() : context.runId,
|
||||
})).resolves.toBe(false);
|
||||
await expect(
|
||||
db
|
||||
.select()
|
||||
@@ -72611,6 +72617,9 @@ describeEmbeddedPostgres("chat channel control-plane integration", () => {
|
||||
try {
|
||||
await locked;
|
||||
await expect(context.repair()).resolves.toBe(false);
|
||||
await expect(recoverCommittedNativeChatResponse(db, {
|
||||
companyId: context.fixture.companyId, issueId: context.issue.id, runId: context.runId,
|
||||
})).rejects.toThrow();
|
||||
await expect(
|
||||
db
|
||||
.select()
|
||||
|
||||
@@ -843,6 +843,21 @@ async function acceptedResponseDigestMatches(
|
||||
export async function repairCommittedNativeChatResponse(
|
||||
db: Db,
|
||||
input: { companyId: string; issueId: string; runId: string },
|
||||
): Promise<boolean> {
|
||||
try {
|
||||
return await recoverCommittedNativeChatResponse(db, input);
|
||||
} catch (error) {
|
||||
logger.warn(
|
||||
{ runId: input.runId, error },
|
||||
"Committed chat response is awaiting presentation retry",
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function recoverCommittedNativeChatResponse(
|
||||
db: Db,
|
||||
input: { companyId: string; issueId: string; runId: string },
|
||||
): Promise<boolean> {
|
||||
let agentId: string | null = null;
|
||||
let materialized = false;
|
||||
@@ -1095,13 +1110,7 @@ export async function repairCommittedNativeChatResponse(
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof CommittedChatResponseAuthorizationError) return false;
|
||||
// Keep transient failures visible and retryable without reclassifying the
|
||||
// committed run or acknowledging a publication that never committed.
|
||||
logger.warn(
|
||||
{ runId: input.runId, error },
|
||||
"Committed chat response is awaiting presentation retry",
|
||||
);
|
||||
return false;
|
||||
throw error;
|
||||
}
|
||||
if (materialized && agentId)
|
||||
publishChatPublicationCommitSignal({
|
||||
|
||||
Reference in new issue
Block a user