feat(boatstack): flow prescribes the owed visual-attachment retry - #257
Merged
Conversation
…equire A plan that promises pixels cannot ship without them. When the approved plan declares pr_visual_evidence relevance relevant with scenarios, the configured suggest policy now ships with require semantics for that feature: publication blocks until current PASS evidence exists — deliberately even when no capture capability is registered (a missing harness is a provisioning gap the denial names, never a license to ship unverified). control-law: plan-approved-scenarios-imply-require - one predicate (visualEscalationApplies) decides escalation; everything downstream reads only the effective policy - context carries pr_visual_evidence_policy_source (configured|plan-escalated); the publication denial says why suggest blocked - escapes stay explicit: off globally, not_relevant + reason per feature - one-time effect: existing suggest+relevant previews report a changed context fingerprint after upgrade (release-noted) Disclosure-Reviewed: reviewed — public-safe only, private facet kept out of this commit
A published PR with Publication.State visual_pending or manual_required previously resolved dark in flow next. Now: - new attach-evidence verb (RetryVisualAttachment): retries exactly the operator-confirmed evidence package against the recorded PR URL; publication authority is never re-asked; idempotent when published; refuses pre-publication manifests (publish-pr owns first publication) - attachVisualEvidence extracted from publishPRVisualEvidence so first publication and the retry record identical states - NextStatus.VisualPublication observed best-effort read-only (frontier-reports-never-mutates); reasons name the owed attachment - prescribeVisualAttach consulted before prescribePostPublish, under BOTH terminals (attaching evidence completes publication, it is not merge pursuit); marker published.attach_evidence never auto-driven - actor typing: visual_pending = agent (work-derivable retry); manual_required = operator (owes a signed-in browser or the observed comment URL); a fired goal escape still demotes and stops Disclosure-Reviewed: reviewed — public-safe only, private facet kept out of this commit
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
When the evidence-comment attachment fails after a PR opens, Boatstack records
visual_pending(ormanual_requiredwith no publisher) and preserves the PR — butflow nextthen resolved toNextOperation: nonewith no prescription: the flow went dark exactly where the fix-forward contract promised a path. This closes the last gap in the program's invariant: capture (#255) and blocking (#256) were deterministic, attachment recovery now is too.What changed
attach-evidence --repo --feature→RetryVisualAttachment: retries exactly the operator-confirmed fingerprinted evidence package against the PR URL recorded at publication — publication authority is never re-asked. Idempotent (published+ comment URL = no-op that never re-consults the publisher). Refuses what it does not own: a pre-publication manifest routes topublish-pr; a missing publisher namesrecord-pr-visual-publicationwith the exact recorded key/PR.attachVisualEvidenceextracted frompublishPRVisualEvidence— first publication and retry record identical states (manual_required/visual_pending/published).NextStatus.VisualPublication— observed best-effort read-only viaobserveVisualPublication(any load error degrades to today's empty answer; only the two owed states surface).control-law: frontier-reports-never-mutatesprescribeVisualAttachconsulted beforeprescribePostPublishand under both terminals — attaching evidence completes the publication itself; it is not merge pursuit.visual_pending→ agent-owned derivable retry;manual_required→ operator-owned recording owing--comment-url. Markerpublished.attach_evidenceis never on the auto-drive allowlist. A fired goal escape prescribes nothing and still demotes.visual-evidenceOwnerVerbs +=attach-evidence; CLI coverage pinned.Invariants pinned
TestOwedVisualAttachmentNeverResolvesDark— the title invariant, including firing under the published default terminal end-to-end throughnextControlFromStatus, and marker-never-driven.next_actor_conformanceadditions —visual_pending=agent,manual_required=operator, escaped pursuit demotes despite the owed attachment.TestRetryVisualAttachmentCompletesOwedPublication/...RefusesWhatItDoesNotOwn— happy path, idempotence, all three refusals, andmanual_requiredrecovery with a live publisher.Note: the retry is keyed per feature (one evidence manifest per feature), so published-slice routing is unaffected — no slice-routing changes needed.
Verification
go build && go vet && go test ./...green. Release note:2026-07-30-visual-attach-retry-prescription.md.Slice 4 of 5; stacked on #256.