docs(spec): correct the gate and hook descriptions that did not reproduce
Four claims in the spec and the hook config stated as fact what the tools
do not do:
- gates.md:485 said factory-audit's validate.sh "holds its own copy of"
the ADR-0020 constants. gates.md:411-413, twenty lines earlier, said it
carries none of them and named the mode libraries. The libraries are
right: lib-checks-skill.sh:313-316 and lib-checks-agent.sh:164-165.
architecture.md repeated the same error.
- gates.md stated the case count for test-adr0020-contract.sh as "29 at
HEAD", explicitly presented as measured. Running it prints 44; 384756b
added the hook-wiring assertions after the text was written.
- gates.md:913 and :916 described "Both audit skills'" behaviour in the
present tense, three and six lines above :919 saying factory-audit's is
the only copy left.
- The apm-audit-ci block named manifest-parse as a check, said the hook
does not scan for hidden Unicode, and called root lockfile-exists
vacuous. apm 0.28.0 runs ten checks, content-integrity does scan for
hidden Unicode, and there is no manifest-parse row.
Also: the version-bump gate's baseline is documented as the single
merge-base it is not -- it resolves every base with merge-base --all,
intersects the changed-skill sets, exempts a tree-identical skill, and
emits a third sha-suffixed failure form. The gate's own header documents
this correctly; the spec did not. Behaviour is unchanged.
The "none of them need the network" line added on this branch cited a
README section that says the opposite for a fresh clone, and the
check-vale-style-sync rationale said 6 of 17 assertions diffed the Vale
copies where ADR-0025 says 2 diffed and 4 more only located them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NwD8Egs5r4ndqeFLmhusX2
This commit is contained in:
@@ -97,48 +97,67 @@ repos:
|
||||
|
||||
- id: apm-audit-ci
|
||||
name: apm audit --ci
|
||||
description: Run apm's producer-side CI gate over the root manifest AND each of the six plugin packages. Verifies exactly two things per manifest -- apm.yml parses as a valid APM manifest (manifest-parse), and, if it declares dependencies, apm.lock.yaml exists and is consistent (lockfile-exists). It does NOT enforce an org policy and does NOT scan for hidden Unicode; see the comment below for why. Reference:plugins/kyberforge/.apm/skills/apm-workflow/references/audit.md
|
||||
description: Run apm's producer-side CI gate over the root manifest AND each of the six plugin packages. On the root manifest it runs ten checks -- lockfile-exists, ref-consistency, deployment-ledger-owners, deployed-files-present, no-orphaned-packages, skill-subset-consistency, config-consistency, content-integrity, includes-consent, drift -- so it is both a hidden-Unicode scan and a drift gate that replays the install and diffs it. In a plugin package it runs one, lockfile-exists. It does NOT enforce an org policy; see the comment below for why. Reference:plugins/kyberforge/.apm/skills/apm-workflow/references/audit.md
|
||||
entry: bash -c 'for d in . plugins/*/; do (cd "$d" && apm audit --ci) || { echo "apm audit --ci failed in $d" >&2; exit 1; }; done'
|
||||
language: system
|
||||
stages: [pre-push]
|
||||
pass_filenames: false
|
||||
always_run: true
|
||||
# The description above deliberately claims less than this hook's old one
|
||||
# did ("lockfile/policy/hidden-content integrity"), because two of those
|
||||
# three were never happening:
|
||||
# What this hook actually runs, read off apm 0.28.0's own compliance
|
||||
# table by invoking `apm audit --ci` at the repo root and in
|
||||
# plugins/lint/. Long form in docs/spec/gates.md, "apm-audit-ci".
|
||||
#
|
||||
# * POLICY. `apm audit --ci` discovers an org policy from the git remote,
|
||||
# and apm's discovery only understands github.com and Azure DevOps.
|
||||
# This repo's remote is a self-hosted Gitea, so discovery resolves
|
||||
# nothing and the run prints `No org policy found at unknown;
|
||||
# enforcement skipped`. apm's own message suggests
|
||||
# `policy.fetch_failure_default=block` in apm.yml "to fail closed" --
|
||||
# that was tried on a scratch copy and REJECTED: it does not make the
|
||||
# check meaningful, it makes it permanently red. `apm audit --ci` then
|
||||
# exits 1 with `No org policy found at unknown
|
||||
# (policy.fetch_failure_default=block)` on every push, because there is
|
||||
# no org policy to find and no supported way for this remote to serve
|
||||
# one. A gate that can never go green is not a gate. Revisit if this
|
||||
# repo ever gains a policy source apm can actually reach.
|
||||
# * HIDDEN CONTENT. The hidden-Unicode scan is plain `apm audit`, not
|
||||
# `apm audit --ci` (the two are different modes, and --ci refuses to
|
||||
# combine with --file/--strip/--dry-run/PACKAGE). Plain `apm audit`
|
||||
# here reports `No apm.lock.yaml found -- nothing to scan` and exits 0,
|
||||
# so adding it would buy a second vacuous check, not coverage.
|
||||
# * ROOT MANIFEST -- ten checks: lockfile-exists, ref-consistency,
|
||||
# deployment-ledger-owners, deployed-files-present,
|
||||
# no-orphaned-packages, skill-subset-consistency, config-consistency,
|
||||
# content-integrity, includes-consent, drift. It is a drift gate: it
|
||||
# replays the install cache-only and diffs the scratch result against
|
||||
# the working tree. Root lockfile-exists is not vacuous -- the root
|
||||
# declares dependencies, so it reports `Lockfile present`.
|
||||
# * PLUGIN MANIFESTS -- one check: lockfile-exists. Conditional, and
|
||||
# vacuous while every plugin apm.yml declares
|
||||
# `dependencies: {apm: [], mcp: []}`: it reports `No dependencies
|
||||
# declared -- lockfile not required` and arms itself the moment one
|
||||
# does not (verified by adding a git dependency to
|
||||
# plugins/lint/apm.yml). Everything else above is root-only, because
|
||||
# only the root install has a lockfile, a deployment ledger and
|
||||
# deployed files to check. Running the six plugin packages is what
|
||||
# makes lockfile-exists reachable for them at all -- the root-only
|
||||
# invocation audits the root manifest and nothing else.
|
||||
# * HIDDEN CONTENT IS COVERED. content-integrity is that scan; it
|
||||
# reports `No critical hidden Unicode or hash drift detected`. An
|
||||
# earlier revision of this comment said the hook does NOT scan for
|
||||
# hidden Unicode and that adding the scan would buy a second vacuous
|
||||
# check. Both claims were wrong. What is true is that the STANDALONE
|
||||
# mode differs: plain `apm audit` (--ci refuses to combine with
|
||||
# --file/--strip/--dry-run/PACKAGE) run in a plugin directory reports
|
||||
# `No apm.lock.yaml found -- nothing to scan` and exits 0, because
|
||||
# only the root has a lockfile.
|
||||
# * MANIFEST-PARSE IS NOT A CHECK in apm 0.28.0's table, and an earlier
|
||||
# revision of this comment named it as one. Parsing is still
|
||||
# enforced -- a dependency entry missing its git/path/registry field
|
||||
# fails with `Cannot parse apm.yml` -- but it fails the invocation
|
||||
# before the table is built, so it never appears as a row.
|
||||
# * POLICY IS NOT ENFORCED. `apm audit --ci` discovers an org policy
|
||||
# from the git remote, and apm's discovery only understands
|
||||
# github.com and Azure DevOps. This repo's remote is a self-hosted
|
||||
# Gitea, so discovery resolves nothing and the run prints `No org
|
||||
# policy found at unknown; enforcement skipped`. apm's own message
|
||||
# suggests `policy.fetch_failure_default=block` in apm.yml "to fail
|
||||
# closed" -- that was tried on a scratch copy and REJECTED: it does
|
||||
# not make the check meaningful, it makes it permanently red. `apm
|
||||
# audit --ci` then exits 1 with `No org policy found at unknown
|
||||
# (policy.fetch_failure_default=block)` on every push, because there
|
||||
# is no org policy to find and no supported way for this remote to
|
||||
# serve one. A gate that can never go green is not a gate. Revisit if
|
||||
# this repo ever gains a policy source apm can actually reach.
|
||||
#
|
||||
# What IS left is worth keeping, and is now run against seven manifests
|
||||
# instead of one. lockfile-exists is conditional -- it is vacuous while
|
||||
# every apm.yml declares `dependencies: {apm: [], mcp: []}`, and it arms
|
||||
# itself the moment one does not (verified: adding a git dependency to
|
||||
# plugins/lint/apm.yml fails with `apm.yml declares dependencies but
|
||||
# apm.lock.yaml is absent`). manifest-parse is unconditional and fires on
|
||||
# any malformed manifest (verified: a dependency entry missing its
|
||||
# git/path/registry field fails with `Cannot parse apm.yml`). Running the
|
||||
# six plugin packages is what makes either reachable for them at all --
|
||||
# the root-only invocation audits the marketplace manifest and nothing
|
||||
# else. Costs ~0.5s per package, needs no network (checked under
|
||||
# `unshare -rn`) -- consistent with every other pre-push hook: none of
|
||||
# them need the network (see README.md's "Offline?" section).
|
||||
# Costs ~0.5s per package. Needs no network ONCE `apm install` has
|
||||
# populated apm_modules/ -- the root marketplace has no remote package
|
||||
# entries, so the install replay is cache-only. On a FRESH CLONE there
|
||||
# is no cache: deployed-files-present fails outright, and drift and
|
||||
# config-consistency clone from the holocron remote. See README.md's
|
||||
# "Offline?" section.
|
||||
|
||||
- id: check-apm-agents-valid
|
||||
name: Validate real APM agent files
|
||||
@@ -167,9 +186,12 @@ repos:
|
||||
pass_filenames: false
|
||||
always_run: true
|
||||
|
||||
# check-vale-style-sync was removed by ADR-0025. Only 6 of its 17
|
||||
# assertions diffed skill-audit's Vale copy against agent-audit's; the
|
||||
# merge into factory-audit leaves one copy, so those are moot. The other
|
||||
# check-vale-style-sync was removed by ADR-0025. Of its 17 assertion
|
||||
# sites only 2 actually diffed skill-audit's Vale copy against
|
||||
# agent-audit's, and 4 more existed solely so the script could locate the
|
||||
# two copies -- a real REPO_ROOT, non-stale .apm/ paths, both copies
|
||||
# present (ADR-0025:285-287). The merge into factory-audit leaves one
|
||||
# copy, so all 6 are moot. The other
|
||||
# 11 moved into tests/test-vale-wrap.sh (case 0, cases 28-31, its
|
||||
# Vale-absent skip, and case 32 for the one-plugin narrowing guard),
|
||||
# which run-tests runs here at
|
||||
|
||||
Reference in New Issue
Block a user