diff --git a/.autonomy/community.yml b/.autonomy/community.yml index 2dadd85..4ba2630 100644 --- a/.autonomy/community.yml +++ b/.autonomy/community.yml @@ -1,6 +1,6 @@ schema: autonomy.openai/v1 -cadenceHours: 24 -maximumLatenessHours: 6 +cadenceHours: 2 +maximumLatenessHours: 1 registeredSourcesOnly: true allowedSourceTypes: - official-repository diff --git a/.autonomy/prompts/coordinator.md b/.autonomy/prompts/coordinator.md index 4a12417..b7a648a 100644 --- a/.autonomy/prompts/coordinator.md +++ b/.autonomy/prompts/coordinator.md @@ -60,18 +60,26 @@ After reconciliation, choose exactly one action in this order: 5. triage and promote pending user Issues; 6. run due post-merge targeted dogfood; 7. run due daily global dogfood; -8. run the due daily community scan; -9. acquire the next trusted executable Issue using `issue-policy.yml`; or -10. enter `idle` after a minimal inbox and recovery check. +8. decompose the next dependency-ready roadmap parent; +9. acquire the next trusted executable Issue using `issue-policy.yml`; +10. run the due community scan; or +11. enter `idle` after a minimal inbox and recovery check. Only that action owns product mutation during the tick. Never work on multiple Issues or product branches concurrently. A severe security Issue may pause ordinary work, but it does not create a second active product mutation. -Community scanning and global dogfood are due every 24 hours. If either is more -than six hours late while a normal Issue spans ticks, run the overdue -non-mutating phase at the next commit boundary without releasing the Issue -lease. Resume development on the following tick. +Community scanning is due every 2 hours and may be at most one hour late. +Select it only when there is no active lease; no resumable pull request, CI, or +post-merge work; no pending user promotion or external intake; no normalized +Issue awaiting activation; no agent-ready Issue; and no roadmap parent awaiting +decomposition. Keep a blocked due scan pending until the next truly idle +coordinator tick. + +Global dogfood is due every 24 hours. If it is more than six hours late while a +normal Issue spans ticks, run the overdue non-mutating phase at the next commit +boundary without releasing the Issue lease. Resume development on the following +tick. ## States diff --git a/tests/unit/autonomy-community-policy.test.ts b/tests/unit/autonomy-community-policy.test.ts new file mode 100644 index 0000000..138c1df --- /dev/null +++ b/tests/unit/autonomy-community-policy.test.ts @@ -0,0 +1,54 @@ +import fs from "node:fs"; +import path from "node:path"; +import { describe, expect, it } from "vitest"; + +const root = path.resolve(import.meta.dirname, "../.."); +const communityPolicy = fs.readFileSync( + path.join(root, ".autonomy/community.yml"), + "utf8", +); +const coordinatorContract = fs.readFileSync( + path.join(root, ".autonomy/prompts/coordinator.md"), + "utf8", +); +const normalizedCoordinatorContract = coordinatorContract.replace(/\s+/g, " "); + +describe("community discovery governance", () => { + it("runs every two hours with at most one hour of lateness", () => { + expect(communityPolicy).toMatch(/^cadenceHours: 2$/m); + expect(communityPolicy).toMatch(/^maximumLatenessHours: 1$/m); + expect(coordinatorContract).toContain( + "Community scanning is due every 2 hours and may be at most one hour late.", + ); + }); + + it("selects community discovery only after executable work and decomposition", () => { + const roadmap = coordinatorContract.indexOf( + "decompose the next dependency-ready roadmap parent", + ); + const executable = coordinatorContract.indexOf( + "acquire the next trusted executable Issue", + ); + const community = coordinatorContract.indexOf("run the due community scan"); + + expect(roadmap).toBeGreaterThan(-1); + expect(executable).toBeGreaterThan(roadmap); + expect(community).toBeGreaterThan(executable); + }); + + it("preserves a due scan until every true-idle blocker is absent", () => { + for (const blocker of [ + "active lease", + "resumable pull request, CI, or post-merge work", + "pending user promotion or external intake", + "normalized Issue awaiting activation", + "agent-ready Issue", + "roadmap parent awaiting decomposition", + ]) { + expect(normalizedCoordinatorContract).toContain(blocker); + } + expect(normalizedCoordinatorContract).toContain( + "Keep a blocked due scan pending until the next truly idle coordinator tick.", + ); + }); +});