Make prompt capture fast and resilient
Hop-State: A_06FN8D0CK06GY5XBDYZ632R Hop-Proposal: R_06FN8CY2FJBV5QA0WFEDWHR Hop-Task: T_06FN8C4PMFJRT8APV4G03Y8 Hop-Attempt: AT_06FN8C4PMFRJEE4B7KKQ740
This commit is contained in:
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"id": "P_06FN8C4PMD47GH10ZFQY2VR",
|
||||||
|
"task_id": "T_06FN8C4PMFJRT8APV4G03Y8",
|
||||||
|
"attempt_id": "AT_06FN8C4PMFRJEE4B7KKQ740",
|
||||||
|
"state_id": "P_06FN8C4PMD47GH10ZFQY2VR",
|
||||||
|
"prompt": "\"I couldn’t safely start the repository change because Hop prompt capture timed out. Per the repository workflow, I stopped before inspecting or modifying files. No changes were made.\" what the fuck is this bullshit",
|
||||||
|
"agent_name": "codex",
|
||||||
|
"status": "proposed",
|
||||||
|
"response_summary": "Make prompt capture fast and resilient",
|
||||||
|
"created_at": "2026-07-12T02:38:18.275042Z",
|
||||||
|
"metadata": {
|
||||||
|
"source_tree": "7f3f889e96a317c157eedf4f5285af835865f6fb",
|
||||||
|
"git_commit": "ff62e89596a85ff3073ea348919b8d2b7125069f",
|
||||||
|
"attempt_head": "C_06FN8CQ0ZNZ60MRZ818MB9G",
|
||||||
|
"attempt_head_kind": "checkpoint"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -655,6 +655,27 @@ func (r *Repository) ReadHiddenRef(ctx context.Context, name string) (oid string
|
|||||||
return r.ReadRef(ctx, ref)
|
return r.ReadRef(ctx, ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListHiddenRefs reads all refs below refs/hop in one Git process. Keys are
|
||||||
|
// relative to refs/hop/ (for example, "states/P_..." or "accepted").
|
||||||
|
func (r *Repository) ListHiddenRefs(ctx context.Context) (map[string]string, error) {
|
||||||
|
output, err := r.run(ctx, nil, nil, "for-each-ref", "--format=%(refname) %(objectname)", hiddenRefPrefix)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
refs := make(map[string]string)
|
||||||
|
for _, line := range strings.Split(strings.TrimSpace(output), "\n") {
|
||||||
|
if line == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
name, oid, found := strings.Cut(line, " ")
|
||||||
|
if !found || !strings.HasPrefix(name, hiddenRefPrefix) {
|
||||||
|
return nil, fmt.Errorf("unexpected hidden ref listing %q", line)
|
||||||
|
}
|
||||||
|
refs[strings.TrimPrefix(name, hiddenRefPrefix)] = strings.TrimSpace(oid)
|
||||||
|
}
|
||||||
|
return refs, nil
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateHiddenRef atomically updates refs/hop/name. With no expectedOld value,
|
// UpdateHiddenRef atomically updates refs/hop/name. With no expectedOld value,
|
||||||
// it is unconditional. Passing expectedOld performs compare-and-swap; an empty
|
// it is unconditional. Passing expectedOld performs compare-and-swap; an empty
|
||||||
// expected value means the ref must not exist.
|
// expected value means the ref must not exist.
|
||||||
|
|||||||
+9
-13
@@ -1640,17 +1640,17 @@ func (s *Service) reconcileDerivedRefs(ctx context.Context, reconcileAccepted bo
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
refs, err := s.Repo.ListHiddenRefs(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
for _, row := range rows {
|
for _, row := range rows {
|
||||||
state := row.State
|
state := row.State
|
||||||
if err := s.Repo.VerifyObjects(ctx, state.GitCommit, state.SourceTree); err != nil {
|
|
||||||
return fmt.Errorf("state %s references unavailable Git data: %w", state.ID, err)
|
|
||||||
}
|
|
||||||
name := "states/" + state.ID
|
name := "states/" + state.ID
|
||||||
commit, exists, err := s.Repo.ReadHiddenRef(ctx, name)
|
if refs[name] != state.GitCommit {
|
||||||
if err != nil {
|
if err := s.Repo.VerifyObjects(ctx, state.GitCommit, state.SourceTree); err != nil {
|
||||||
return err
|
return fmt.Errorf("state %s references unavailable Git data: %w", state.ID, err)
|
||||||
}
|
}
|
||||||
if !exists || commit != state.GitCommit {
|
|
||||||
if err := s.Repo.UpdateHiddenRef(ctx, name, state.GitCommit); err != nil {
|
if err := s.Repo.UpdateHiddenRef(ctx, name, state.GitCommit); err != nil {
|
||||||
return fmt.Errorf("repair Git pin for state %s: %w", state.ID, err)
|
return fmt.Errorf("repair Git pin for state %s: %w", state.ID, err)
|
||||||
}
|
}
|
||||||
@@ -1668,11 +1668,7 @@ func (s *Service) reconcileDerivedRefs(ctx context.Context, reconcileAccepted bo
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
commit, exists, err := s.Repo.ReadHiddenRef(ctx, acceptedRef)
|
if refs[acceptedRef] != head.GitCommit {
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !exists || commit != head.GitCommit {
|
|
||||||
if err := s.Repo.UpdateHiddenRef(ctx, acceptedRef, head.GitCommit); err != nil {
|
if err := s.Repo.UpdateHiddenRef(ctx, acceptedRef, head.GitCommit); err != nil {
|
||||||
return fmt.Errorf("repair accepted Git ref: %w", err)
|
return fmt.Errorf("repair accepted Git ref: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-2
@@ -58,8 +58,13 @@ uses it as the default session and identifies the runtime as `codex` unless
|
|||||||
headers, and credential-bearing connection strings before persistence.
|
headers, and credential-bearing connection strings before persistence.
|
||||||
|
|
||||||
Read the returned `HOP_STATE_ID`, `HOP_TASK_ID`, `HOP_ATTEMPT_ID`, and workspace.
|
Read the returned `HOP_STATE_ID`, `HOP_TASK_ID`, `HOP_ATTEMPT_ID`, and workspace.
|
||||||
If capture fails or `hop` is unavailable, stop without project effects and
|
Allow at least 120 seconds for capture. If it times out or fails transiently,
|
||||||
report the error.
|
retry once with the same message, agent, and session; Hop session binding makes
|
||||||
|
the retry idempotent for the task. If the retry fails, inspect Hop's error and
|
||||||
|
locks, run `hop doctor`, and repair a safe local operational problem when
|
||||||
|
possible. Stop without project effects only when Hop remains unavailable or
|
||||||
|
unsafe after recovery; do not abandon the user's request after the first
|
||||||
|
timeout.
|
||||||
|
|
||||||
If Hop reports redactions, never repeat the credential in output, summaries,
|
If Hop reports redactions, never repeat the credential in output, summaries,
|
||||||
commands recorded as evidence, or proposal text. Refer to its environment
|
commands recorded as evidence, or proposal text. Refer to its environment
|
||||||
|
|||||||
Reference in New Issue
Block a user