feat(seo): resolve agentic sites from agent.json, deprecate SEO_AGENTIC_SITES #298

Merged
joshtronic merged 1 commit from feat/seo-agentic-agentjson into master 2026-06-30 16:13:39 +00:00
Collaborator

PR 1 of the agent-ification work (foundation; no per-repo config depends on it yet).

What

Moves the agentic-SEO opt-in out of the SEO_AGENTIC_SITES env map and into each repo's agent.json — the per-repo dossier automerge already reads .smoke.url and feedback reads .feedback.csv from:

{ "seo": { "domain": "vpsshowdown.com", "agentic": true } }

seo_agentic_repo_for moves to lib/seo-analysis.sh (so it's unit-testable, like its analysis siblings) and resolves the GSC domain → repo by scanning bot-accessible repos for one whose .seo.domain matches and .seo.agentic is true.

Migration safety

SEO_AGENTIC_SITES stays as a deprecated fallback — used only when no agent.json .seo matches, and it logs once when it fires. So there's zero regression while the per-repo agent.json configs roll out, and when that log goes quiet we know every agentic repo is on agent.json and can delete the env var, its export, and the host .env line.

Tests

bin/test-seo-agentic.sh (new): agent.json match + precedence over the env, the agentic:true gate, the env fallback, no-match. make test green (check-sync + all 9 unit tests).

Next in this series

  • PR 2: CEO pulls GSC on-demand for any repo with .seo.domain — real numbers in the digest (answers the CEO's #37).
  • PR 3+: add agent.json .seo + drafted CEO.md mandates across the 8 target repos, piloting vps-showdown first.
**PR 1 of the agent-ification work** (foundation; no per-repo config depends on it yet). ## What Moves the agentic-SEO opt-in out of the `SEO_AGENTIC_SITES` env map and into each repo's `agent.json` — the per-repo dossier `automerge` already reads `.smoke.url` and `feedback` reads `.feedback.csv` from: ```json { "seo": { "domain": "vpsshowdown.com", "agentic": true } } ``` `seo_agentic_repo_for` moves to `lib/seo-analysis.sh` (so it's unit-testable, like its analysis siblings) and resolves the GSC domain → repo by scanning bot-accessible repos for one whose `.seo.domain` matches and `.seo.agentic` is true. ## Migration safety `SEO_AGENTIC_SITES` stays as a **deprecated fallback** — used only when no `agent.json .seo` matches, and it **logs once when it fires**. So there's zero regression while the per-repo `agent.json` configs roll out, and when that log goes quiet we know every agentic repo is on `agent.json` and can delete the env var, its export, and the host `.env` line. ## Tests `bin/test-seo-agentic.sh` (new): agent.json match + precedence over the env, the `agentic:true` gate, the env fallback, no-match. `make test` green (check-sync + all 9 unit tests). ## Next in this series - **PR 2:** CEO pulls GSC on-demand for any repo with `.seo.domain` — real numbers in the digest (answers the CEO's #37). - **PR 3+:** add `agent.json .seo` + drafted `CEO.md` mandates across the 8 target repos, piloting vps-showdown first.
feat(seo): resolve agentic sites from agent.json, deprecate SEO_AGENTIC_SITES
All checks were successful
Lint / check-sync (push) Successful in 5s
Lint / check-sync (pull_request) Successful in 4s
39bea58c63
The SEO pass decided which GSC domain is "agentic" (gets a curated Agent ticket)
from the SEO_AGENTIC_SITES env map ("domain=owner/repo|..."). Move that opt-in
into each repo's agent.json -- the same per-repo dossier automerge reads
`.smoke.url` and feedback reads `.feedback.csv` from:

    { "seo": { "domain": "<gsc-domain>", "agentic": true } }

seo_agentic_repo_for moves to lib/seo-analysis.sh and now resolves domain->repo
by scanning bot-accessible repos for one whose `.seo.domain` matches and
`.seo.agentic` is true. That same field also feeds the CEO's on-demand GSC read
(follow-up PR).

SEO_AGENTIC_SITES is kept as a DEPRECATED fallback (used only when no agent.json
`.seo` matches) and logs once when it fires -- so when that log goes quiet,
every agentic repo is on agent.json and the env var, its export, and the host
`.env` line can be deleted. No regression while the per-repo configs roll out.

Adds bin/test-seo-agentic.sh (agent.json match + precedence, the agentic gate,
and the env fallback). make test green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011KXPafSYJPY6XkWHHk1Lfs
Author
Collaborator

🤖 Review — COMMENT (automated)

CI for 39bea58c: success

Moves seo_agentic_repo_for from bin/tick.sh into lib/seo-analysis.sh, reimplements it to resolve the agentic SEO domain from each repo's agent.json .seo block (primary) with SEO_AGENTIC_SITES kept as a logged, deprecated fallback, and adds a focused unit-test file. The code is clean, in scope (~130 lines), and well-tested; CI is green. I'm withholding APPROVE on a couple of things I can't confirm from the diff alone, none of which clearly block.

What checks out

  • New seo_agentic_repo_for logic is correct: graceful degradation on forgejo_list_bot_repos/jq failure (|| repos=""), per-repo || continue guards play well with set -e, .seo.agentic gate uses string "true" consistent with jq -r ... // false, env fallback word-splits on | via local IFS, and the deprecation log fires only when the env actually resolves.
  • The old definition is removed from tick.sh (no duplicate/shadowing), and the signature is unchanged, so existing call sites keep working.
  • The test file exercises all the claimed cases (agent.json match, agentic:false gate, domain mismatch, env fallback, agent.json-precedence-over-env, no-match, and .seo-absent ignore). I traced each — they should pass. Checklist matches the diff honestly.
  • No security concerns, no CI-workflow changes.

Reservations for a human to weigh (non-blocking)

  • Behavioral change in cost. Resolution goes from a zero-cost env-map lookup to listing all bot repos and fetching each repo's agent.json over the Forgejo API per call. The author argues the once-per-domain-per-month cadence makes this acceptable, which is reasonable, but it's a real shift in runtime/network behavior (and a new failure surface: a transient forgejo_repo_get_file failure on the matching repo silently falls through to the env, and post-migration that means no resolution that tick). Worth an owner's awareness.
  • Call site not in the diff. The actual invocation of seo_agentic_repo_for in tick.sh isn't shown, so I can't directly confirm lib/seo-analysis.sh is sourced before it's called. It almost certainly is (other seo_* lib functions are used by the same flow), but I can't verify the runtime integration from the diff.
  • Test wiring unverified. The "9 unit tests / make test green" claim implies bin/test-*.sh is auto-discovered by the test runner; no Makefile/runner change is in the diff. CI success is consistent with auto-discovery, but I can't see it.

None of these are defects I'd block on — flagging them so the human can confirm the integration point and sign off on the new API-call behavior.


Independent review by the harness on claude-opus-4-8. The human reviewer is requested once Igor has reviewed; a human still merges.

### 🤖 Review — `COMMENT` _(automated)_ CI for `39bea58c`: **success** Moves `seo_agentic_repo_for` from `bin/tick.sh` into `lib/seo-analysis.sh`, reimplements it to resolve the agentic SEO domain from each repo's `agent.json` `.seo` block (primary) with `SEO_AGENTIC_SITES` kept as a logged, deprecated fallback, and adds a focused unit-test file. The code is clean, in scope (~130 lines), and well-tested; CI is green. I'm withholding APPROVE on a couple of things I can't confirm from the diff alone, none of which clearly block. **What checks out** - New `seo_agentic_repo_for` logic is correct: graceful degradation on `forgejo_list_bot_repos`/`jq` failure (`|| repos=""`), per-repo `|| continue` guards play well with `set -e`, `.seo.agentic` gate uses string `"true"` consistent with `jq -r ... // false`, env fallback word-splits on `|` via `local IFS`, and the deprecation `log` fires only when the env actually resolves. - The old definition is removed from `tick.sh` (no duplicate/shadowing), and the signature is unchanged, so existing call sites keep working. - The test file exercises all the claimed cases (agent.json match, `agentic:false` gate, domain mismatch, env fallback, agent.json-precedence-over-env, no-match, and `.seo`-absent ignore). I traced each — they should pass. Checklist matches the diff honestly. - No security concerns, no CI-workflow changes. **Reservations for a human to weigh (non-blocking)** - **Behavioral change in cost.** Resolution goes from a zero-cost env-map lookup to listing all bot repos and fetching each repo's `agent.json` over the Forgejo API per call. The author argues the once-per-domain-per-month cadence makes this acceptable, which is reasonable, but it's a real shift in runtime/network behavior (and a new failure surface: a transient `forgejo_repo_get_file` failure on the matching repo silently falls through to the env, and post-migration that means no resolution that tick). Worth an owner's awareness. - **Call site not in the diff.** The actual invocation of `seo_agentic_repo_for` in `tick.sh` isn't shown, so I can't directly confirm `lib/seo-analysis.sh` is sourced before it's called. It almost certainly is (other `seo_*` lib functions are used by the same flow), but I can't verify the runtime integration from the diff. - **Test wiring unverified.** The "9 unit tests / make test green" claim implies `bin/test-*.sh` is auto-discovered by the test runner; no Makefile/runner change is in the diff. CI success is consistent with auto-discovery, but I can't see it. None of these are defects I'd block on — flagging them so the human can confirm the integration point and sign off on the new API-call behavior. --- <sub>Independent review by the harness on `claude-opus-4-8`. The human reviewer is requested once Igor has reviewed; a human still merges.</sub> <!-- review sha=39bea58c630c563615fd40dcd56f7e8be13b0cb5 verdict=COMMENT ci=success -->
igor added spent time 2026-06-30 16:09:40 +00:00
1 minute 39 seconds
joshtronic approved these changes 2026-06-30 16:13:35 +00:00
joshtronic deleted branch feat/seo-agentic-agentjson 2026-06-30 16:13:39 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No assignees
2 participants
Notifications
Total time spent: 1 minute 39 seconds
igor
1 minute 39 seconds
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
joshtronic/igor!298
No description provided.