Enable §3 issues-as-state (dual-write) + §7 votable health by default, + read-only/gh-api hardening#550
Merged
Merged
Conversation
§3 issues-as-state is now ON by default as a safe dual-write transition. STATE_BACKEND becomes tri-state: dual (default) appends each run event to the pinned aeon:cron-state Issue AND keeps committing cron-state.json — readers unchanged, zero staleness risk, while the Issue store is exercised live; issues = append + skip the file/rebase loop (churn-free end state, gated materialize handles the reader cutover); file = legacy escape hatch. Append failures always fall through to the file path. §7 votable health Issues is ON by default (opt out with HEALTH_ISSUES=0). It is silent on clean runs, so a healthy fleet still creates zero issues; regressions auto-open a votable per-skill Issue. Default run path now writes to the Issue store; the pinned issue is pre-created (#549) so ensure() never races. Graduate to STATE_BACKEND=issues once dual-write is proven to drop the commit churn. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…eads) read-only drops all gh because gh is a write vector and Bash(gh:*) is all-or-nothing — even gh api GET reads are excluded. A read-only skill needing GitHub data should use WebFetch/curl on api.github.com or stay write. Notes the two graceful degraders (github-trending, security-digest — gh api is a fallback behind a curl/WebFetch primary). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…n issues The issues-as-state ledger (`aeon:cron-state`) is machine-managed and append-only, so there's no reason for it to sit in the repo's open-issues list forever. GitHub allows commenting on and reading a *closed* issue (only locking blocks comments), so the ledger works just as well closed — invisibly. - `ensure` now searches `--state all` (finds the ledger whether open or closed) - on creation it closes the issue immediately; appends still land on it - aeon manages the lifecycle on-demand: first run creates+closes it, no human pin Verified live against GitHub: create+close, append to closed issue, fold, and dedup re-ensure all pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
aaronjmars
added a commit
that referenced
this pull request
Jun 25, 2026
… 0 disabled it (#552) #550 made §7 votable-health "default-on" via `if: ... && vars.HEALTH_ISSUES != '0'`. But GitHub Actions `if:` comparisons do numeric coercion: an UNSET repo var is null, and `null != '0'` evaluates as `0 != 0` → false. So with HEALTH_ISSUES unset (the default), the step was SKIPPED on every run — §7 was silently default-OFF, the exact opposite of the intent. Caught on a fork canary: the analyzer correctly scored a deliberately-bad skill 1 + `empty_output`, yet no health issue was filed because the step never ran. Fix: gate the step only on `always() && steps.skill.outputs.name != ''` (proven by the sibling "Update cron state" step) and move the toggle into bash — `if [ "${{ vars.HEALTH_ISSUES }}" = "0" ]; then exit 0; fi` — a string compare with no coercion, matching how STATE_BACKEND is handled. Verified on a fork: re-dispatch then opened `health: <skill>` issue #5 with the regression comment. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
aaronjmars
added a commit
that referenced
this pull request
Jun 25, 2026
…runner (#553) Two bugs the fork canary surfaced on the chain path (chains are unused on prod today, so these were latent): 1. Missing `issues: write` — the §3 issues-as-state append (added in #548/#550) calls the Issues API via state_store.sh. chain-runner only had contents+actions write, so the append 403'd: chain run-events never reached the ledger Issue (dual mode masked it via the file path; `issues` mode would have lost them). 2. Sub-run discovery regex `test("skill: ${skill}(")` — the literal '(' is an unterminated regex group (jq throws "end pattern with unmatched parenthesis") and only appears in run titles when a skill has a var ("skill: digest (x)"). Var-less steps ("skill: heartbeat") never matched, so dispatch_skill timed out and the chain aborted at step 1. Fixed to `test("skill: ${skill}( |$)")` — matches name-then-space (var) or name-then-end (no var). Verified end-to-end on a fork: a 2-step heartbeat chain now completes green — both sub-runs discovered + awaited, and "chain state appended to issue #N (backend=dual)" succeeds. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
aaronjmars
added a commit
that referenced
this pull request
Jun 25, 2026
…554) The hardening features shipped in #548/#550 were undocumented. Add operator/author docs for the three user-facing ones: - README "It heals itself": votable health (`HEALTH_ISSUES`, `health: <skill>` issues, 👍/👎 to set repair priority). - README Advanced: "Capability tiers (read-only skills)" (`mode:` frontmatter) and "Durable state without the churn" (`STATE_BACKEND` dual/issues/file). - docs/CAPABILITIES.md: a "Runtime enforcement: the `mode:` write tier" section — the runtime gate that complements the install-time `capabilities:` taxonomy. - docs/CORE.md + docs/status.md: votable-health notes in the self-healing loop and the public /status/ health page. No code changes — documentation only. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Makes §3 and §7 on by default, implemented safely, plus the read-only/
gh apiand ensure()-race hardening. Builds on #548.§3 issues-as-state — ON by default (dual-write transition)
STATE_BACKENDis now tri-state:dual(default, unset)aeon:cron-stateIssue AND keep committingcron-state.json— readers unchanged, zero staleness risk, Issue store exercised liveissuesfileThis is hardening item #3 (the dual-write transition): the file stays authoritative, so even total failure of the Issue path can't corrupt or stale the readers. Append failures always fall through to the file. Graduate to
STATE_BACKEND=issuesto drop the commit churn once dual-write is proven.§7 votable health Issues — ON by default
Flipped to default-on (
HEALTH_ISSUES != '0'; opt out with=0). Silent on clean runs, so a healthy fleet still creates zero Issues — only regressions auto-open a votable per-skill Issue.Hardening
gh api— documented inskill_mode.sh: read-only excludes allgh(incl. GET reads) by design; GitHub reads should use WebFetch/curl onapi.github.comor staywrite. The two affected skills (github-trending,security-digest) usegh apionly as a fallback, so they degrade gracefully.ensure()race — pre-created the pinnedaeon:cron-stateIssue (aeon:cron-state #549) soensure()always finds it and never races to create a duplicate under concurrency.Safety / testing
materialize+ commit-drop fire only on explicitissues, sodualkeeps the file fresh.skill_modesuite still green.gh issue comment(append) — the file path is otherwise unchanged.🤖 Generated with Claude Code