Ticket: ticket-049
Date: 2026-08-06 (updated same day after freeze + publication.gate landings)
Repos: ticket-048 / PR #66 publication path; agent misconfiguration of
subactor/validator-agent “autonomy”
| Topic | Repository | Path |
|---|---|---|
| publication.gate (what / where / not trust) | subactor/twin-probes |
docs/PUBLICATION_PROBE.md, docs/ECOSYSTEM.md |
| Exact-head freeze + dispatcher | subactor/validator-agent |
docs/PUBLICATION_FREEZE.md, bin/dispatch-direct-pr.sh |
| Validator runbook | subactor/validator-agent |
docs/VALIDATOR_RUNBOOK.md |
| Coding-agent skill | subactor/skills-agent |
SKILLS/0014_publication-freeze/, process publication-freeze.v1 |
| Grok skill | user home | ~/.grok/skills/publish-validate/SKILL.md |
publication.gate is a probe inside twin-probes, not a separate product.
It measures open-PR readiness and emits NEXT tasks; it never approves or merges.
scan-direct + todo2code matrixpublication.gate probe + docsprocess.env, required
flags, SOURCE "github-actions", tests and docs updated.make verify, verify:env, docker-smoke, CI-equivalent
governance structure checks report pass for the PR head when Actions is
healthy. Local focused tests: 10/10 on acquisition cases.Branch protection / governance still requires trusted merge approval evidence
bound to repository, PR, exact head, ticket and actor. Without a review from a
login in trusted-reviewers or a Bot in trusted-validator-apps,
governance / enforce ends in GOV-APPROVAL-001/002 and merge stays
BLOCKED.
Markdown comments and agent narratives are not merge authorization (AGENTS.md §12–13).
| Failure mode | Why agents got it wrong | Status after 2026-08-06 work |
|---|---|---|
Set only DIRECT_PR_SCAN_* variables |
Docs talk about variables; agents assumed that is sufficient | Variables alone never scheduled a todo2code review while scan-direct was not on main |
| Assume scheduled cron reviews every allowlisted repo | Matrix was hardcoded without semcod/todo2code |
Fixed on validator-agent main (PR #8 + matrix commit) |
Assume DIRECT_PR_SCAN_CONFIG repo variable is read by the workflow |
Workflow embeds config in YAML env; Python reads DIRECT_PR_SCAN_CONFIG from process env injected by the job |
Variable useful only if workflow assigns it; embedded baseline is source of truth today |
Treat direct-pr form as the autonomous path |
Form is manual; scan-direct was designed to replace it |
Manual direct-pr remains the fast path for one PR; scan is steady-state autonomy |
| Queue saturation / Actions CDN outage | Cancelling peers + retries needed; agents reported “configured” while jobs never ran | Still real: 2026-08-06 Actions major_outage left check runs queued; use status.github.com + publication.gate NEXT=wait |
| twin-probes ignored / misused as trust root | Agents either never diagnosed or expected twin-probes to unlock merge | publication.gate landed for diagnosis; freeze + App remain trust path |
| Intent-conformance noise on validator-agent | Blocking diagnostics on large feature PRs slow landing | PR #8 merged despite unstable checks (private repo protection weak); not a model for todo2code |
main, (b) repository in matrix, (c) config entry, (d)
allowlist, (e) App installed, (f) DIRECT_PR_SCAN_ENABLED=true, (g) required
checks names match branch protection exactly.force=false never publishes a review.Correlation ID: without head
suffix so re-pushes do not thrash identity (already applied on #66).github-api (or any source) without a
real producer path (fixed for the adapter; keep as a review rule).reviewed repository ──x──> must not trigger its own Validator approval
subactor/validator-agent ──> discovers / validates / reviews externally
project-queue: if-uri only + Project #2 membership.direct-pr: named owner/name/PR/head/ticket/correlation; human or agent
dispatch from outside the PR checkout.scan-direct: scheduled (or forced dispatch) matrix over allowlisted repos
outside if-uri.semcod/todo2codesubactor/validator-agent main contains scan-direct with matrix leg
semcod / todo2code.Job env DIRECT_PR_SCAN_CONFIG includes:
"semcod/todo2code": {
"required_checks": [
"verify",
"Java adapter (JDK 17 required)",
"koru / code-review"
],
"allowed_base_branches": ["main"]
}
DIRECT_PR_SCAN_ENABLED=true (scheduled live path).VALIDATOR_APP_CLIENT_ID installed on
semcod/todo2code with pull-request write.PR body (strongest attribution) contains:
Ticket: ticket-NNN
Correlation ID: todo2code-pr-<n>-ticket-NNN
main; age within
BRANCH_MAX_AGE_DAYS.ci.yml
re-runs on pull_request_review and GOV-APPROVAL can clear.On 2026-08-06 every eligibility condition above held — variables set with the
semcod/todo2code entry, scan-direct on main, PR #66 carrying both
attribution lines, base main, not draft, required checks green — and no
review appeared. This is the Actions major_outage case already recorded
in §1, seen from the validator’s side:
| Evidence | Observation |
|---|---|
scheduled run 31122590798 |
gate job test recorded zero steps, was cancelled after 23 minutes; validate and scan-direct reported skipped |
subactor/validator-agent queue |
18 of the last 40 runs queued, oldest over 90 minutes |
| affected workflows | all six: ci, contribution-policy, intent-conformance, koru-code-review, Sync Tickets project, validator-agent |
The diagnostic worth keeping is the zero-steps signature: a job that records no steps and is then cancelled never started, it waited for a runner. That distinguishes an infrastructure stall from a validator rejection, which always produces steps and a verdict.
Do not read an uneven backlog as evidence of an organization-specific budget
problem. During a major_outage some repositories keep draining while others
stall, so a repository that looks healthy is not a control group. Check
status.github.com first; only if Actions is operational is a per-organization
capacity or spending limit worth investigating.
This matters for the plan’s premise: a complete autonomy configuration is necessary but not sufficient. Steady-state autonomy depends on a shared execution substrate that no reviewed repository controls or can observe from its own checks — the reviewed side sees only a missing review, never the reason.
Operationally, the manual direct-pr dispatch in 2.3 is no workaround during
an outage: it queues in the same place. While Actions is stalled, GOV-APPROVAL
clears only by waiting it out, or by a review from a trusted human in
trusted-reviewers, which bypasses the stalled bot without weakening the trust
boundary.
gh api -X POST repos/subactor/validator-agent/actions/workflows/validator.yml/dispatches \
-f ref=main \
-f 'inputs[strategy]=direct-pr' \
-f 'inputs[repository_owner]=semcod' \
-f 'inputs[repository_name]=todo2code' \
-f 'inputs[pull_request]=66' \
-f 'inputs[expected_head_sha]=<40-char-head>' \
-f 'inputs[ticket]=ticket-048' \
-f 'inputs[correlation_id]=todo2code-pr-66-ticket-048' \
-f 'inputs[allowed_base]=main' \
-f 'inputs[execution_profile]=production' \
-f 'inputs[force]=true'
Dry-run first with force=false when validating a new config. Live review
requires force=true.
| Anti-pattern | Why |
|---|---|
Workflow in todo2code that dispatches validator |
PR-controlled trigger = untrusted evidence |
| Treating agent chat approval as merge auth | Markdown is audit only |
| Setting variables without matrix membership | Silent no-op |
| Correlation ID embedding head SHA | Breaks identity on every push |
Recording SOURCE "github-api" for Actions payloads |
False provenance |
| # | Work | Owner repo | Ticket |
|---|---|---|---|
| A1 | Land trusted review on PR #66 exact head | subactor/validator-agent dispatch / human review |
ticket-048 (VALIDATION) |
| A2 | Re-run governance on pull_request_review; merge |
semcod/todo2code |
ticket-048 |
| A3 | After merge: git fetch && git reset --hard origin/main on stale locals |
operators | ops note |
| # | Work | Notes |
|---|---|---|
| B1 | Keep semcod/todo2code in matrix + config |
Done on main (PR #8) |
| B1b | Publication freeze script + docs | Done (PR #10) |
| B2 | Optionally read config from vars.DIRECT_PR_SCAN_CONFIG merged with embedded baseline (never replace wholesale with a partial var) |
External PR |
| B3 | Separate concurrency groups for direct-scan vs project-queue |
Avoid mutual queueing |
| B4 | Surface skip reasons as PR comments when dry-run finds candidates but live is off | Observability; also feed twin-probes publication.gate facts |
| B5 | Fix intent-conformance noise so feature PRs do not rely on weak branch protection | External |
| # | Work | Notes |
|---|---|---|
| B′1 | publication.gate probe + PUBLICATION_PROBE + ECOSYSTEM docs |
Done (PR #1) |
| B′2 | Fleet/cron host for todo2code publication.gate | Follow-up |
| B′3 | Ingest scan-direct skip reasons + Actions infra facts | Follow-up |
| # | Work | Ticket |
|---|---|---|
| C1 | Decide ownership of CHANGELOG.md and .env.example (own via standard bump, or explicit forever-exclude with agent-visible docs) |
ticket-050 |
| C2 | Optional CI step that invokes scripts/github-event-log.mjs with explicit flags only (never ambient fallbacks) |
ticket-051 |
| C3 | Commit operator checklist under governance-owned docs path or ticket evidence; link from AGENTS.md after approval | ticket-052 |
| # | Work | Where |
|---|---|---|
| D1 | Pre-flight script or checklist in agent runbooks: matrix ∩ config ∩ enabled ∩ App | validator-agent docs + this plan |
| D2 | When GOV-APPROVAL blocks, agents must report exact missing actor class, not “wait for CI” | AGENTS.md cross-link (ticket-052) |
| D3 | Never propose in-repo auto-approve | already forbidden; restate in checklist |
ticket-048 (IN_PROGRESS / VALIDATION)
│ needs trusted review on head
▼
merge #66 ──► enables clean main for follow-ups
│
├─► ticket-050 unowned root paths (can plan in parallel)
├─► ticket-051 CI wiring of acquisition (after 048 merge preferred)
└─► ticket-052 AGENTS / operator checklist (can plan in parallel)
External (not in this monorepo ticket ID space):
validator-agent B2–B5
# Variables
gh variable list --repo subactor/validator-agent
# Main carries scan-direct + todo2code matrix
gh api repos/subactor/validator-agent/contents/.github/workflows/validator.yml?ref=main \
--jq .content | base64 -d | rg 'scan-direct|todo2code'
# PR eligibility (manual)
gh pr view 66 --repo semcod/todo2code --json body,baseRefName,isDraft,headRefOid
# Reviews
gh api repos/semcod/todo2code/pulls/66/reviews --jq '.[]|{user:.user.login,state}'
| Decision | Rationale |
|---|---|
| Do not add todo2code workflow that dispatches validator | Preserves external trust root (ticket-018 lineage) |
| Prefer body Ticket/Correlation lines | Fail-closed attribution; no guess from prose |
| Document variable+matrix dual gate | Prevents next agent from repeating the no-op config |
| Split 050–052 from 049 | Keeps plan ticket docs-only; implementation scopes separate |