Skip to content

Decisions proposed during --replay look like live ones #36

Closed

Description

@shipmill-romamo

What happens

cloudfall agent investigate --replay <recording> (#34) plays recorded check output back to a live model. Decisions the model proposes during a replay are saved in --decisions like real ones, and nothing in the decision record says their check output was played back; only the investigation record names the replay.

An operator could approve one of these as if its check had run on the host.

Expected

A decision proposed during a replay can't be mistaken for a live one. Options raised in the review of #34 (#34 (comment)):

  1. Mark replayed decision records (for example a replay field naming the recording), and refuse or warn on approving one
  2. Write replayed decisions to a separate default folder
  3. Leave it as is

Activity

  1. shipmill-romamo commented on Oct 8, 2026

    @shipmill-romamo
    ContributorAuthor

    Triage: implement, once the design below is settled. Waits on your decision in the next comment.

    Confirmed on main (9cb777c):

    • agent investigate --replay (sdk/src/cloudfall/app.py, agent_investigate) swaps the check runner for the recording, but --decisions keeps its default, so decisions proposed in a replay are saved in the same folder as live ones
    • The decision record has no field naming the replay; only the investigation record has replay. decisions list, why and decisions approve can't tell them apart
    • A second trap: a recording is a decisions directory. Run with --replay decisions and the default --decisions decisions, and the replay writes its new records into the recording it is playing back. Recording.load keeps the first run of each call, so this mostly doesn't change later replays, but a call the recording didn't hold is saved there with exit 3 and its "replay: ... holds no run" output

    Design. This changes stored state (the decision record) and maybe a default, so it goes through the design gate. No decisions log exists yet. The decision record schema is also changed by #37 (approval.via) and maybe #26 (status values), so whichever lands second rebases on the other.

    Compatibility for every option: records written before the change carry no replay marker and read as live, which they were.

  2. shipmill-romamo commented on Oct 8, 2026

    @shipmill-romamo
    ContributorAuthor

    @romamo Decision needed: how should a decision proposed during agent investigate --replay be kept apart from a live one?

    1. Mark it, and refuse to approve it (recommended): the decision record gets a replay field naming the recording, decisions list and why show it, and decisions approve refuses it with PRECONDITION (its check output was played back, not run). --replay also refuses a --decisions folder that is the recording itself. Additive schema field
    2. Mark it and only warn on approve: same field, but approving still works after a warning. Keeps a replayed proposal usable as a real one, at the cost of the gate trusting output that never came from the host
    3. Separate folder: with --replay, --decisions defaults to something like tmp/replay/decisions instead, and records are not marked. Nothing in the schema changes, but a record copied or pointed at by hand looks live again
    4. Leave it as is

    Reply here with a number or your own answer; shipmill takes this up on the tick after your reply.

  3. romamo commented on Oct 9, 2026

    @romamo
    Collaborator

    1 — mark it with a replay field and have decisions approve refuse it with PRECONDITION; --replay also refuses a --decisions folder that is the recording itself

    (decision by @romamo, given in chat; posted by Claude on his behalf)

  4. shipmill-romamo commented on Oct 9, 2026

    @shipmill-romamo
    ContributorAuthor

    Triage: implement, taking up the answer above (option 1), recorded as D-2 in #51.

    Plan: a decision proposed during agent investigate --replay gets an optional replay field naming the recording (additive in the v1 schema; older records have none and read as live); decisions list and why show it; decisions approve refuses it with PRECONDITION; --replay refuses a --decisions folder that resolves to the recording itself.

    #26 also changes operation-decision.schema.json; the same implementer builds both on separate branches, and whichever merges second rebases on the other.

  5. removed
    needs-decisionA shipmill session asked a question here; waits for a reply
    on Oct 9, 2026
  6. shipmill-romamo commented on Oct 9, 2026

    @shipmill-romamo
    ContributorAuthor

    PR: #55. A decision proposed during --replay carries replay (the path as given to --replay, the same value the investigation record stores); decisions list and why show it; decisions approve refuses it with PRECONDITION / decision_replayed before asking for the id; --replay refuses a --decisions folder that resolves to the recording. #53 (#26) touches the same files, so the second to merge gets rebased.

  7. romamo commented on Oct 9, 2026

    @romamo
    Collaborator

    Decision by @romamo, given in chat; posted by Claude on his behalf.

    1. Mark it and refuse to approve it: the decision record gets a replay field naming the recording, decisions list and why show it, decisions approve refuses it with PRECONDITION, and --replay refuses a --decisions folder that is the recording itself.

  8. added a commit that references this issue on Oct 9, 2026
    64ccf81
  9. shipmill-romamo commented on Oct 9, 2026

    @shipmill-romamo
    ContributorAuthor

    Released in v0.6.0rc9.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions