Context
React on Rails PR #4749 reconciles its vendored agent-workflow seam to immutable shakacode/agent-workflows commit 1958648b70a450aa67c15b833428485d17021045. Review and replay found six fail-open or ambiguous contracts that belong upstream. The consumer sync did not introduce them and should keep pack-identical helpers byte-identical instead of adding consumer-only overlays.
Problems and expected behavior
1. Unknown pr-ci-readiness buckets are accepted (script)
skills/pr-batch/bin/pr-ci-readiness treats an unrecognized check-row bucket as a successful row. A row such as {"workflow":"CI","name":"mystery","bucket":"future-state"} currently produces READY when it is the only required row. Missing or non-object row fields are likewise not validated before readiness classification.
Expected: fail closed when a fetched check row is structurally invalid or has an unknown bucket. Only explicitly recognized successful/skipped buckets may contribute to READY, and the result must explain why readiness is UNKNOWN or NOT_READY.
Reproduction:
PrCiReadiness.assess(
pr_number: 1,
required_used: true,
rows: [{ "workflow" => "CI", "name" => "mystery", "bucket" => "future-state" }]
)
# Current verdict: READY
This behavior was reproduced against old consumer pin 4bb0c1e4944276e271799fd179e0c166b54ef4dc and the reconciled pack line.
2. Trust-role values accept malformed types (schema)
agent-workflow-seam-doctor normalizes trusted_bots and trusted_metadata_bots with Array(value) and to_s. Hashes, numbers, mixed arrays, and empty entries therefore become apparent logins instead of being rejected. A numeric scalar such as 42 can become the login "42".
Expected: accept a legacy nonempty string or an array containing only nonempty strings, then apply the existing normalization and cross-role overlap check. Reject every other shape before normalization. Cover the same schema at all trust-config consumption seams.
3. status: not_applicable can satisfy required priority evidence (schema)
closeout-evidence-replay --require-priority-dispositions rejects an empty status: not_applicable marker, but the same marker with a valid P1 finding returns SATISFIED.
Observed at the reconciled head:
overall_verdict: SATISFIED
priority verdict: SATISFIED
status: not_applicable
finding count: 1
missing: []
errors: []
Expected: the status and finding shape must be internally consistent. Required-mode priority evidence containing status: not_applicable must never produce SATISFIED, including when a syntactically valid finding is appended.
4. Fresh dispatch approval persists stale refresh provenance (script)
When a persisted dispatch-decision-refresh is followed by a fresh dispatch-decision, selection uses the new authority but history_resolution retains the old refresh resolution.
Observed:
selected status: selected
selected authority: {dispatch: false, route: true}
persisted action: dispatch-decision-refresh
persisted decision id: refresh-before-dispatch
replay without transient operator_decision: blocked-user-input
Expected: the fresh dispatch decision supersedes the prior refresh resolution, persists its decision id/action/updated authority, and replays to the same selected assignment without transient operator input.
5. Explicit GH_HOST does not verify the resolved repository URL host (script)
pr-security-preflight requests both nameWithOwner and url, but its explicit-GH_HOST branch validates only the slug and then assigns the expected host without parsing the returned URL. A same-slug response from a different host can therefore be accepted and misclassify repository-local trust state.
Expected: canonicalize and compare both the returned slug and URL host with the requested repository and explicit GH_HOST; fail closed on either mismatch. Add a same-slug/different-host regression.
6. Completed-audit refs and OUTSTANDING comma fallback are ambiguous (schema)
The completed-batch-audit v1 grammar reserves ; and | inside record refs but permits commas, while findings: OUTSTANDING ... uses comma splitting as a fallback. A multi-ref findings value containing a valid comma-bearing record ref cannot be parsed into a unique blocker identity.
Expected: make the grammar unambiguous everywhere it is documented, parsed, mirrored, and tested. One acceptable mechanism is reserving commas in refs; another is removing comma fallback in favor of an unambiguous delimiter. Preserve canonical ref normalization and blocker-union completeness.
Acceptance coverage
- Unknown, missing, null, and non-object readiness rows fail closed; existing pass, skip, pending, fail, and cancel behavior remains covered.
- Trust config accepts only legacy nonempty scalar strings or arrays of nonempty strings and rejects malformed/mixed shapes before normalization.
- Required priority evidence cannot be satisfied by
status: not_applicable, with or without findings.
- Refresh-then-dispatch persists the fresh approval and restart replay succeeds without transient operator state.
- Explicit-host security preflight rejects same-slug payloads whose repository URL resolves to another host.
- Completed-audit parsing has one documented and tested, non-ambiguous ref grammar across pack copies.
- Each regression is demonstrated red before the fix and green after it against the immutable pack source.
Mechanism disposition
- Targets:
script for readiness, dispatcher persistence, and host verification; schema for trust roles, priority evidence consistency, and completed-audit refs.
- Motivating miss: machine-checkable readiness, trust, replay, and blocker identities currently accept unknown, contradictory, stale, or ambiguous state.
- Replay evidence: React on Rails PR #4749 review threads and the concrete reproductions above at head
04c1b8149e4bf6f7ccb8edd41f8e478d78bdfcc6.
- Non-goals: consumer-only overlays; changing pull-request trust boundaries;
pull_request_target; optional final-candidate edge nits concerning absolute-path npm invocation, pathological post-SIGKILL reaping, or mutable documentation links.
Context
React on Rails PR #4749 reconciles its vendored agent-workflow seam to immutable
shakacode/agent-workflowscommit1958648b70a450aa67c15b833428485d17021045. Review and replay found six fail-open or ambiguous contracts that belong upstream. The consumer sync did not introduce them and should keep pack-identical helpers byte-identical instead of adding consumer-only overlays.Problems and expected behavior
1. Unknown
pr-ci-readinessbuckets are accepted (script)skills/pr-batch/bin/pr-ci-readinesstreats an unrecognized check-rowbucketas a successful row. A row such as{"workflow":"CI","name":"mystery","bucket":"future-state"}currently producesREADYwhen it is the only required row. Missing or non-object row fields are likewise not validated before readiness classification.Expected: fail closed when a fetched check row is structurally invalid or has an unknown bucket. Only explicitly recognized successful/skipped buckets may contribute to
READY, and the result must explain why readiness isUNKNOWNorNOT_READY.Reproduction:
This behavior was reproduced against old consumer pin
4bb0c1e4944276e271799fd179e0c166b54ef4dcand the reconciled pack line.2. Trust-role values accept malformed types (
schema)agent-workflow-seam-doctornormalizestrusted_botsandtrusted_metadata_botswithArray(value)andto_s. Hashes, numbers, mixed arrays, and empty entries therefore become apparent logins instead of being rejected. A numeric scalar such as42can become the login"42".Expected: accept a legacy nonempty string or an array containing only nonempty strings, then apply the existing normalization and cross-role overlap check. Reject every other shape before normalization. Cover the same schema at all trust-config consumption seams.
3.
status: not_applicablecan satisfy required priority evidence (schema)closeout-evidence-replay --require-priority-dispositionsrejects an emptystatus: not_applicablemarker, but the same marker with a valid P1 finding returnsSATISFIED.Observed at the reconciled head:
Expected: the status and finding shape must be internally consistent. Required-mode priority evidence containing
status: not_applicablemust never produceSATISFIED, including when a syntactically valid finding is appended.4. Fresh dispatch approval persists stale refresh provenance (
script)When a persisted
dispatch-decision-refreshis followed by a freshdispatch-decision, selection uses the new authority buthistory_resolutionretains the old refresh resolution.Observed:
Expected: the fresh dispatch decision supersedes the prior refresh resolution, persists its decision id/action/updated authority, and replays to the same selected assignment without transient operator input.
5. Explicit
GH_HOSTdoes not verify the resolved repository URL host (script)pr-security-preflightrequests bothnameWithOwnerandurl, but its explicit-GH_HOSTbranch validates only the slug and then assigns the expected host without parsing the returned URL. A same-slug response from a different host can therefore be accepted and misclassify repository-local trust state.Expected: canonicalize and compare both the returned slug and URL host with the requested repository and explicit
GH_HOST; fail closed on either mismatch. Add a same-slug/different-host regression.6. Completed-audit refs and
OUTSTANDINGcomma fallback are ambiguous (schema)The
completed-batch-audit v1grammar reserves;and|inside record refs but permits commas, whilefindings: OUTSTANDING ...uses comma splitting as a fallback. A multi-ref findings value containing a valid comma-bearing record ref cannot be parsed into a unique blocker identity.Expected: make the grammar unambiguous everywhere it is documented, parsed, mirrored, and tested. One acceptable mechanism is reserving commas in refs; another is removing comma fallback in favor of an unambiguous delimiter. Preserve canonical ref normalization and blocker-union completeness.
Acceptance coverage
status: not_applicable, with or without findings.Mechanism disposition
scriptfor readiness, dispatcher persistence, and host verification;schemafor trust roles, priority evidence consistency, and completed-audit refs.04c1b8149e4bf6f7ccb8edd41f8e478d78bdfcc6.pull_request_target; optional final-candidate edge nits concerning absolute-path npm invocation, pathological post-SIGKILLreaping, or mutable documentation links.