Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
af8c7d6
feat: implement issue #647 — [Phase 4] Promotion mechanism: informati…
donpetry-bot Sep 7, 2026
f94a5cf
Merge branch 'main' into dev-lead/issue-647-20260907-1558
don-petry Sep 7, 2026
316357f
Merge branch 'main' into dev-lead/issue-647-20260907-1558
don-petry Sep 7, 2026
b5d7abe
Merge branch 'main' into dev-lead/issue-647-20260907-1558
don-petry Sep 8, 2026
1b4de5b
Merge branch 'main' into dev-lead/issue-647-20260907-1558
don-petry Sep 8, 2026
2877da2
Merge branch 'main' into dev-lead/issue-647-20260907-1558
don-petry Sep 8, 2026
6af3b11
Merge branch 'main' into dev-lead/issue-647-20260907-1558
don-petry Sep 10, 2026
533836d
Merge branch 'main' into dev-lead/issue-647-20260907-1558
don-petry Sep 10, 2026
4284abf
Merge branch 'main' into dev-lead/issue-647-20260907-1558
don-petry Sep 13, 2026
40bf392
Merge branch 'main' into dev-lead/issue-647-20260907-1558
don-petry Sep 13, 2026
919ef71
Merge branch 'main' into dev-lead/issue-647-20260907-1558
don-petry Sep 13, 2026
b8365b2
Merge branch 'main' into dev-lead/issue-647-20260907-1558
don-petry Sep 13, 2026
376b2d1
Merge branch 'main' into dev-lead/issue-647-20260907-1558
don-petry Sep 16, 2026
bad1faa
Merge branch 'main' into dev-lead/issue-647-20260907-1558
don-petry Sep 16, 2026
f556f8e
Merge branch 'main' into dev-lead/issue-647-20260907-1558
don-petry Sep 20, 2026
ac39dd0
Merge branch 'main' into dev-lead/issue-647-20260907-1558
don-petry Sep 20, 2026
091e1dc
Merge branch 'main' into dev-lead/issue-647-20260907-1558
don-petry Sep 20, 2026
96ceff6
Merge branch 'main' into dev-lead/issue-647-20260907-1558
don-petry Sep 20, 2026
d84d1dc
Merge branch 'main' into dev-lead/issue-647-20260907-1558
don-petry Sep 21, 2026
5deca16
Merge branch 'main' into dev-lead/issue-647-20260907-1558
don-petry Sep 23, 2026
5d37261
Merge branch 'main' into dev-lead/issue-647-20260907-1558
don-petry Sep 23, 2026
c991baf
Merge branch 'main' into dev-lead/issue-647-20260907-1558
don-petry Sep 23, 2026
8231168
chore: dev-lead update (review-changes) [skip ci-relay]
don-petry Sep 23, 2026
fab9dff
fix: address CodeRabbit review findings for cycle-log validation
don-petry Sep 23, 2026
eb00c59
fix(reviews): address review comments [skip ci-relay]
don-petry Sep 23, 2026
c5fb20e
fix(docs): clarify row-collapsing behavior in cycle-log validation doc
don-petry Sep 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions .github/workflows/agents-md-rules-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
# Triggered on any PR (and main push) that touches:
# - scripts/lib/agents-md-rules.json
# - scripts/agents-md-lint.sh
# - scripts/agents-md-cycle-log.sh
# - docs/initiatives/agents-md-validation-cycle-log.md
# - tests/test_agents_md_rules_config.bats
# - tests/agents_md_lint.bats
# - tests/agents_md_cycle_log.bats
# - tests/fixtures/agents-md/**
# - .github/workflows/agents-md-rules-tests.yml
#
Expand All @@ -19,7 +22,11 @@
# a source + date, and the informational->blocking promotion gate encodes two
# clean cycles plus maintainer sign-off. It also runs tests/agents_md_lint.bats,
# which exercises the Phase-2 linter's pure helpers over synthetic fixtures (a
# valid AGENTS.md plus one per failure mode) with no network.
# valid AGENTS.md plus one per failure mode) with no network, and
# tests/agents_md_cycle_log.bats, which exercises the Phase-4 (#647) append-only
# cycle-log reader/validator (scripts/agents-md-cycle-log.sh): every recorded
# determination names a maintainer, and the clean-cycle precondition is reported
# without ever promoting.
#
# Context: reference doc docs/initiatives/agents-md-validation.md (#643 Phase 1,
# #644 Phase 2 of epic #642). Phase 1 delivered the data file; Phase 2 adds the
Expand All @@ -34,8 +41,11 @@ on:
paths:
- 'scripts/lib/agents-md-rules.json'
- 'scripts/agents-md-lint.sh'
- 'scripts/agents-md-cycle-log.sh'
- 'docs/initiatives/agents-md-validation-cycle-log.md'
- 'tests/test_agents_md_rules_config.bats'
- 'tests/agents_md_lint.bats'
- 'tests/agents_md_cycle_log.bats'
- 'tests/fixtures/agents-md/**'
- '.github/workflows/agents-md-rules-tests.yml'
push:
Expand All @@ -44,8 +54,11 @@ on:
paths:
- 'scripts/lib/agents-md-rules.json'
- 'scripts/agents-md-lint.sh'
- 'scripts/agents-md-cycle-log.sh'
- 'docs/initiatives/agents-md-validation-cycle-log.md'
- 'tests/test_agents_md_rules_config.bats'
- 'tests/agents_md_lint.bats'
- 'tests/agents_md_cycle_log.bats'
- 'tests/fixtures/agents-md/**'
- '.github/workflows/agents-md-rules-tests.yml'

Expand Down Expand Up @@ -79,4 +92,5 @@ jobs:
run: |
bats --print-output-on-failure \
tests/test_agents_md_rules_config.bats \
tests/agents_md_lint.bats
tests/agents_md_lint.bats \
tests/agents_md_cycle_log.bats
66 changes: 66 additions & 0 deletions docs/initiatives/agents-md-validation-cycle-log.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# AGENTS.md Structural Check — Append-Only Cycle Log

- **Purpose:** the durable, tamper-evident, independently-auditable record of each Standards Sync / compliance-audit
cycle's AGENTS.md **structural** finding count and every **confirmed false-positive** determination, each attributed
to a named maintainer. This log — not the editable summary issue — is the source of truth for the
"two consecutive clean cycles" precondition of the informational → blocking promotion gate.
- **Epic / story:** [#642](https://github.com/petry-projects/.github/issues/642) ·
[#647 — Phase 4: promotion mechanism](https://github.com/petry-projects/.github/issues/647).
- **Reference doc:** [`agents-md-validation.md`](./agents-md-validation.md) — §4 documents the promotion gate this log feeds.
- **Reader / validator:** [`scripts/agents-md-cycle-log.sh`](../../scripts/agents-md-cycle-log.sh)
(`validate` and `eligibility` — pure, tested, and it never promotes).

---

## Rules — this file is append-only

1. **Append only. Never edit or delete a recorded row.** Each cycle is a permanent baseline fact. Corrections are made by
appending a new row **that reuses the same `Cycle` date** as the row it supersedes. The `Cycle` date is the stable
identity of a cycle: `agents-md-cycle-log.sh`'s `eligibility` function collapses rows by `Cycle` date and counts
only the **last** row recorded for each date, so a same-date correction supersedes the earlier row and each cycle is
counted exactly once — a correction never inflates the distinct-cycle count. (Do **not** give a correction a new date;
that would be counted as a separate cycle.) The `validate` function, by contrast, checks every row individually — a row
that fails any validation invariant stays permanently invalid even after a well-formed same-date correction is appended,
so a validation-failing row must itself be corrected or the log remains ineligible. The original stays visible in git
history, which is what makes the record tamper-evident and independently auditable. Silently editing or removing a past
row defeats the entire purpose of the gate and will be treated as tampering.
2. **Every determination names a maintainer.** The **Determined by** cell must name the maintainer (GitHub `@handle`) who
reviewed the cycle and confirmed the false-positive count — including a clean (zero false positives) cycle. A row with
no named maintainer is invalid; `agents-md-cycle-log.sh validate` fails on it. A "clean cycle" claim may never be
anonymous.
3. **Finding counts come from the audit summary, not from memory.** The **Structural findings** count is the informational
AGENTS.md structural-findings count reported by that cycle's compliance-audit summary
([`scripts/compliance-audit.sh`](../../scripts/compliance-audit.sh)). Copy it verbatim; do not restate or round it.
4. **Clean? is derived, not asserted.** `Clean?` is `yes` **iff** the confirmed-false-positive count is `0`. The validator
rejects a row whose flag contradicts its count.
5. **Adding a row is a reviewable PR.** Because the log is committed, appending a cycle is a normal pull request a
maintainer reviews — the same human gate used for the other codified org policy.

## How a cycle is recorded

After each compliance-audit cycle:

1. Read the **AGENTS.md Structural Findings (informational)** section of that cycle's audit summary issue; note the
structural finding count.
2. A maintainer reviews the listed structural findings and decides which, if any, are **confirmed false positives**
Comment thread
don-petry marked this conversation as resolved.
(a finding the deterministic linter raised that is not in fact a structural defect).
3. Append one row below with the cycle date, the finding count, the confirmed-false-positive count and details, the
maintainer's `@handle`, and the derived `Clean?` flag — in a pull request. **Escape any literal `|` in the
False-positive details cell as `\|`** so it stays inside the cell and does not shift later columns; the reader restores
the escaped pipe when it parses the row. A nonzero false-positive count must record what was confirmed — an empty (or
placeholder `—`) details cell fails `validate`.
4. `scripts/agents-md-cycle-log.sh eligibility docs/initiatives/agents-md-validation-cycle-log.md 2` then reports whether the
clean-cycle precondition is met. Meeting it is **not** a promotion — see the gate in the reference doc.

---

## Cycle records

<!-- APPEND-ONLY: add new cycles at the bottom; never edit or remove a row above. -->

| Cycle | Structural findings | Confirmed false positives | False-positive details | Determined by | Clean? |
|-------|---------------------|---------------------------|------------------------|---------------|--------|

_No cycles recorded yet. The promotion gate's clean-cycle precondition is therefore **not** met, so the structural check
ships and remains **informational**. The first row is appended after the first compliance-audit cycle runs and a
maintainer reviews its structural findings._
64 changes: 60 additions & 4 deletions docs/initiatives/agents-md-validation.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
# Initiative: AGENTS.md Structural Validation — Rule Set & Spec-Alignment Reference

- **Status:** Phase 1 (documentation + rule set only) — the rule set is **inert on merge**; no linter, workflow, or audit consumes it yet.
- **Date:** 2026-09-01
- **Status:** Phase 4 (promotion **mechanism** + documentation) — the structural check is wired into the compliance audit
**informational-only**; Phase 4 adds the per-cycle record, the append-only cycle log, and the discrete blocking toggle,
but **arms nothing**. The check remains non-blocking on merge; promotion to blocking is a separate, human-gated decision.
- **Date:** 2026-09-01 (Phase 1) · Phase 4 promotion mechanism added 2026-09-07
- **Epic:** [#642 — AGENTS.md Specification Alignment & Automated Structural Validation](https://github.com/petry-projects/.github/issues/642)
- **Story:** [#643 — Phase 1: Define the AGENTS.md structural rule set and spec-alignment reference](https://github.com/petry-projects/.github/issues/643)
- **Story:** [#643 — Phase 1: Define the AGENTS.md structural rule set and spec-alignment reference](https://github.com/petry-projects/.github/issues/643);
[#647 — Phase 4: informational → blocking promotion mechanism](https://github.com/petry-projects/.github/issues/647)
- **Sources:** discussion [#534 — AGENTS.md Specification Alignment & Automated Validation](https://github.com/petry-projects/.github/discussions/534);
idea [#341 — Cross-Repo Standards Drift Detection via Multi-Repo Analysis](https://github.com/petry-projects/.github/discussions/341)
- **Rule set:** [`scripts/lib/agents-md-rules.json`](../../scripts/lib/agents-md-rules.json)
Expand Down Expand Up @@ -142,12 +145,65 @@ Two further guarantees:
- **Section-presence rules stay `recommended` for now.** The exact required-vs-recommended split for section presence is an open question in epic #642;
starting them advisory avoids hard-requiring a contested section list before it is confirmed.

### 4.1 How "two consecutive clean cycles" is recorded — the append-only cycle log

The clean-cycle count must be **independently auditable and tamper-evident**, so it does **not** live only in the editable
audit summary issue (which could be silently edited to fabricate a clean-cycle claim). Instead, each cycle's structural
finding count and every confirmed false-positive determination are appended to a committed, append-only log:

- **Cycle log:** [`docs/initiatives/agents-md-validation-cycle-log.md`](./agents-md-validation-cycle-log.md).
- **Reader / validator:** [`scripts/agents-md-cycle-log.sh`](../../scripts/agents-md-cycle-log.sh) — a pure, bats-tested
helper with two subcommands: `validate` (every recorded determination is attributed to a GitHub `@handle` — arbitrary
attribution text such as `Alice` is rejected; the finding and false-positive counts are non-negative integers; the
false-positive count never exceeds the finding count; a nonzero false-positive count carries non-empty details; and the
`Clean?` flag agrees with the false-positive count) and `eligibility` (reports whether the last two cycles are clean).
**It never promotes** — it only reports the precondition.

The chain of custody:

1. Each compliance-audit cycle's summary section states the machine-counted **structural findings this cycle**.
2. A maintainer reviews those findings and decides which, if any, are **confirmed false positives**.
3. The maintainer appends one row to the cycle log — finding count, confirmed-false-positive count and details, their
Comment thread
don-petry marked this conversation as resolved.
`@handle`, and the derived `Clean?` flag — in a reviewable pull request. **Every determination, including a clean
cycle, names the maintainer who made it.** Rows are never edited or deleted; git history is the tamper-evidence.
4. `scripts/agents-md-cycle-log.sh eligibility docs/initiatives/agents-md-validation-cycle-log.md 2` then reports whether
the clean-cycle precondition is met. **Meeting it is not a promotion** — sign-off and the discrete flip below are still required.

### 4.2 The discrete blocking toggle — delivered here, armed nowhere

Promotion is a discrete, reviewable change gated behind the criteria above. This story (#647) delivers the **mechanism**
and leaves it **disabled** (`promotion.toggle.enabled` is `false` in the rule set). Two independent points must be armed
to enforce, and **this story arms neither**:

| Toggle point | What flipping it does | State in this story |
|--------------|-----------------------|---------------------|
| **Linter failing mode** — [`scripts/agents-md-lint.sh`](../../scripts/agents-md-lint.sh) `--mode failing` | The linter exits non-zero on a `required`-level finding instead of report-only. The compliance audit invokes it informational-only today; a reviewable change would route required findings to a failing check. | Not enabled — audit stays informational. |
| **Required status check** — branch protection | The local canonical-AGENTS.md CI self-check becomes a **required status check** on `main` (see [`standards/github-settings.md`](https://github.com/petry-projects/.github/blob/main/standards/github-settings.md)). | Not applied — no branch-protection change in this story. |

The flip itself remains a human decision recorded against the documented criteria: two clean cycles in the cycle log
**and** explicit maintainer sign-off. Neither the audit, the linter, nor the cycle-log helper ever performs it automatically.

### 4.3 Maintainer promotion checklist

When both preconditions are genuinely met, a maintainer promotes the check by, in a single reviewable PR:

1. Confirming `agents-md-cycle-log.sh eligibility …` reports `clean-cycles-met=true` over the required two cycles.
2. Recording explicit sign-off (the approving maintainer) in the PR description, referencing the two clean cycle-log rows.
3. Flipping the toggle: set `promotion.default_severity` to `blocking` and `promotion.toggle.enabled` to `true` in the
rule set, wire the audit / CI self-check to `--mode failing`, and add the required status check per `standards/github-settings.md`.

Until that PR merges, the check is informational and no AGENTS.md structural finding can fail a run.

---

## 5. References

- [`scripts/lib/agents-md-rules.json`](../../scripts/lib/agents-md-rules.json) — the machine-readable rule set (this initiative's data artifact).
- [`scripts/lib/agents-md-rules.json`](../../scripts/lib/agents-md-rules.json) — the machine-readable rule set (this initiative's data artifact), including the `promotion` gate and its `toggle`.
- [`docs/initiatives/agents-md-validation-cycle-log.md`](./agents-md-validation-cycle-log.md) — the append-only, committed per-cycle log behind the clean-cycle precondition (Phase 4, #647).
- [`scripts/agents-md-cycle-log.sh`](../../scripts/agents-md-cycle-log.sh) — pure reader/validator for the cycle log (`validate` + `eligibility`); reports the precondition, never promotes.
- [`scripts/compliance-audit.sh`](../../scripts/compliance-audit.sh) — records this cycle's structural finding count in the audit summary and points at the cycle log (Phase 4, #647).
- [`tests/test_agents_md_rules_config.bats`](../../tests/test_agents_md_rules_config.bats) — contract tests for the rule set.
- [`tests/agents_md_cycle_log.bats`](../../tests/agents_md_cycle_log.bats) — contract tests for the cycle-log reader/validator.
- [`.github/workflows/agents-md-rules-tests.yml`](../../.github/workflows/agents-md-rules-tests.yml) — CI gate that runs the contract tests.
- [`.dev-lead/scripts/aw-standards-sync.sh`](../../.dev-lead/scripts/aw-standards-sync.sh) — the presence-only compliance framework this initiative extends.
- [`AGENTS.md`](../../AGENTS.md) — the canonical org-level file the import-consistency rule points downstream repos back to.
Expand Down
Loading
Loading