Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
26 changes: 1 addition & 25 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,28 +26,4 @@ jobs:
run: python -m pip install --quiet --upgrade pip pytest pyyaml

- name: Run action-contract tests
run: python -m pytest tests/ -q --ignore=tests/test_herald_renderer.py

# The Herald renderer is behavioral, not just structural: it shells the real
# `decided decisions-for --json` (published asdecided-core — the same contract the
# wrapper consumes in the field, ADR-063) and must render byte-identical
# comments for the same corpus and diff. Kept out of the structural job so
# that tier stays engine-free.
herald-renderer:
name: herald renderer (published engine)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5

- uses: actions/setup-python@v6
with:
python-version: "3.12"

- name: Install test deps
run: python -m pip install --quiet --upgrade pip pytest

- name: Install the verified native engine
run: bash shared/install-native.sh 0.23.1

- name: Run the renderer battery
run: python -m pytest tests/test_herald_renderer.py -q
run: python -m pytest tests/ -q
24 changes: 19 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ member) this consolidates the CI wrappers that previously lived in `asdecided-co
in the standalone `rac-actions` / `lore-watchkeeper` / `lore-gatekeeper` repos.

Every capability is a **thin wrapper over the public `decided` CLI** (ADR-063);
all analysis and policy live in the native engine. The wrappers download a
checksum-verified `asdecided-core` release (pin with the
`asdecided-version` input). Python is used only by Herald's comment renderer,
not as the engine.
all analysis, policy, and Herald rendering live in the native engine. The
wrappers download a checksum-verified `asdecided-core` release (pin with the
`asdecided-version` input). No action requires a Python runtime.

## Capabilities

Expand All @@ -19,8 +18,9 @@ not as the engine.
| Watchkeeper | [`watchkeeper/github/`](watchkeeper/github/) | `decided watchkeeper` (PR knowledge review) | `uses: asdecided/ci/watchkeeper/github@<ref>` |
| Gatekeeper | [`gatekeeper/github/`](gatekeeper/github/) | `decided gate --sarif` (required merge gate) | `uses: asdecided/ci/gatekeeper/github@<ref>` |
| Registrar | [`registrar/github/`](registrar/github/) | `decided validate --sarif` (well-formedness, ADR-058) | `uses: asdecided/ci/registrar/github@<ref>` |
| Herald | [`herald/github/`](herald/github/) | `decided decisions-for --json` (advisory governing-decisions comment on PRs) | `uses: asdecided/ci/herald/github@<ref>` |
| Herald | [`herald/github/`](herald/github/) | `decided herald` (advisory governing-decisions comment on PRs) | `uses: asdecided/ci/herald/github@<ref>` |
| Recordkeeper | [`recordkeeper/`](recordkeeper/) | read-access audit recorder (ADR-084) | *placeholder — not yet shipped* |
| Sentry | [`sentry/github/`](sentry/github/) | `decided sentry --sarif` (deterministic decision-to-code enforcement) | `uses: asdecided/ci/sentry/github@<ref>` |

A reusable Watchkeeper workflow is also published at
[`.github/workflows/watchkeeper.yml`](.github/workflows/watchkeeper.yml)
Expand All @@ -30,6 +30,20 @@ A reusable Watchkeeper workflow is also published at
demanded; the engine is already platform-neutral (SARIF/JSON), so that work is in
the wrappers, not the engine.

## Distribution facades

Development remains in this repository. Marketplace-facing repositories are
generated release facades so each action can carry a root `action.yml`:

`asdecided/gatekeeper`, `asdecided/herald`, `asdecided/recordkeeper`,
`asdecided/registrar`, `asdecided/watchkeeper`, and `asdecided/sentry`.

`distribution/actions.json` is the source manifest and
`scripts/package-facades.sh <empty-output-directory>` builds all six
deterministically. Recordkeeper is packaged as a companion-repository
placeholder but is not marked Marketplace-ready until its execution wrapper
ships; the other five contain root action manifests.

## History

The `watchkeeper/`, `gatekeeper/`, and `registrar/` wrappers moved here from
Expand Down
11 changes: 11 additions & 0 deletions distribution/actions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"schema_version": 1,
"facades": [
{"name": "gatekeeper", "source": "gatekeeper/github", "marketplace": true},
{"name": "herald", "source": "herald/github", "marketplace": true},
{"name": "recordkeeper", "source": "recordkeeper", "marketplace": false},
{"name": "registrar", "source": "registrar/github", "marketplace": true},
{"name": "watchkeeper", "source": "watchkeeper/github", "marketplace": true},
{"name": "sentry", "source": "sentry/github", "marketplace": true}
]
}
18 changes: 9 additions & 9 deletions gatekeeper/github/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@
# The Watchkeeper action lives at `watchkeeper/github/` and the validate
# (Registrar) action at `registrar/github/`; this gate is referenced as
# `uses: asdecided/ci/gatekeeper/github@<ref>`.
name: "RAC PR gate"
name: "As Decided Gatekeeper"
description: >-
Enforce a requirements-as-code (RAC) corpus on a pull request with a single
Enforce an As Decided knowledge corpus on a pull request with a single
`decided gate` command — validation, relationship integrity, and review under the
corpus enforcement policy — surfaced inline via GitHub Code Scanning (SARIF) as
a required status check. A thin wrapper over the `rac` CLI.
a required status check. A thin wrapper over the native `decided` CLI.
author: "Tom Ballard"

branding:
Expand All @@ -26,9 +26,9 @@ branding:

inputs:
path:
description: "The RAC corpus directory to enforce (passed to `decided gate`)."
description: "The As Decided corpus directory to enforce."
required: false
default: "rac"
default: "decisions"
upload-sarif:
description: >-
Upload SARIF to GitHub Code Scanning (`true` or `false`). Requires the job
Expand All @@ -43,7 +43,7 @@ inputs:
description: >-
Verified native asdecided-core release to install.
required: false
default: "0.23.1"
default: "0.24.0"

runs:
using: "composite"
Expand Down Expand Up @@ -79,7 +79,7 @@ runs:
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: ${{ inputs.sarif-dir }}/gate.sarif
category: rac-gate
category: asdecided-gatekeeper

# Any non-zero CLI exit fails the check; the Code Scanning annotations show
# every finding, blocking and advisory. What is blocking is decided by the
Expand All @@ -90,7 +90,7 @@ runs:
EXIT_CODE: ${{ steps.gate.outputs.exit_code }}
run: |
if [ "$EXIT_CODE" != "0" ]; then
echo "::error::RAC PR gate failed (exit $EXIT_CODE) — see the Code Scanning annotations."
echo "::error::As Decided Gatekeeper failed (exit $EXIT_CODE) — see Code Scanning annotations."
exit "$EXIT_CODE"
fi
echo "RAC PR gate passed."
echo "As Decided Gatekeeper passed."
28 changes: 12 additions & 16 deletions herald/github/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
#
# Proclaims the recorded decisions that govern a pull request's changed paths
# as ONE advisory comment: compute the merge-base diff, run
# `decided decisions-for --json` per changed path (the live-decisions lookup the
# CLI and MCP serve, `decision-to-code-proximity`), and post a terse,
# native `decided herald` renderer (built on the live-decisions lookup the CLI
# and MCP serve, `decision-to-code-proximity`), and post a terse,
# deduplicated comment that re-runs update in place. Facts, never verdicts
# (ADR-034): the comment names what governs and recommends review; it never
# gates the merge — the action succeeds whatever it finds, and only
Expand All @@ -22,21 +22,21 @@
# `pull-requests: write` on the job for the comment. On forks, where the
# token is read-only, the comment falls back to the step summary instead of
# failing the check.
name: "AsDecided decisions on PR"
name: "As Decided Herald"
description: >-
Comment the recorded decisions that govern a pull request's changed paths —
id, title, and the declared scope that matched — as one advisory,
update-in-place comment. A thin wrapper over `decided decisions-for`; facts,
update-in-place comment. A thin wrapper over `decided herald`; facts,
never a merge gate.
author: "Tom Ballard"
branding:
icon: "book-open"
color: "purple"
inputs:
path:
description: "The RAC corpus directory (passed to `decided decisions-for`)."
description: "The As Decided corpus directory."
required: false
default: "rac"
default: "decisions"
max-inline:
description: >-
Governing decisions listed in full before the rest collapse into a
Expand All @@ -47,13 +47,10 @@ inputs:
description: >-
Verified native asdecided-core release to install.
required: false
default: "0.23.1"
default: "0.24.0"
runs:
using: "composite"
steps:
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install AsDecided
shell: bash
run: |
Expand All @@ -74,9 +71,8 @@ runs:
fi
git diff --name-only "$BASE_SHA...$HEAD_SHA" > lore-changed-paths.txt
echo "$(wc -l < lore-changed-paths.txt) changed path(s)"
# One deterministic comment body: `decided decisions-for --json` per changed
# path, merged by decision id, sorted, no wall-clock input — the same
# bytes for the same corpus and diff.
# The native engine owns collection, deduplication, sorting, and rendering.
# The same corpus and diff produce the same bytes; no Python sidecar.
- name: Render governing decisions
id: render
shell: bash
Expand All @@ -85,12 +81,12 @@ runs:
MAX_INLINE: ${{ inputs.max-inline }}
LINK_BASE: ${{ github.server_url }}/${{ github.repository }}/blob/${{ github.event.pull_request.head.sha }}
run: |
python "$GITHUB_ACTION_PATH/render.py" \
--corpus "$INPUT_PATH" \
decided herald "$INPUT_PATH" \
--paths-file lore-changed-paths.txt \
--link-base "$LINK_BASE" \
--max-inline "$MAX_INLINE" \
--out lore-decisions-comment.md
--out lore-decisions-comment.md \
--github-output "$GITHUB_OUTPUT"
# One comment per PR, updated in place on re-runs (found by its marker).
# No comment is created when nothing governs; an existing comment is
# updated even to the empty state, so it never goes stale. A read-only
Expand Down
164 changes: 0 additions & 164 deletions herald/github/render.py

This file was deleted.

Loading