From 00474a6c26f89ac95ab90323a21cb732e04100f4 Mon Sep 17 00:00:00 2001 From: Brett Date: Thu, 30 Apr 2026 22:56:37 -0500 Subject: [PATCH 1/9] docs: fix stale docs/design refs after layout split (#61 follow-up) (#62) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary PR #61 moved shipped artifacts (`foundation.css`, `og.html`, `og.css`) out of `docs/design/` and research/concept work into `docs/research/design/`, but left stale references to the old paths in: - `docs/DESIGN.md` — 17+ refs (would 404 on github.com when browsed on `main`). - `scripts/og/og.css` — internal header comment block. - `tests/e2e/flows.e2e.ts` — single comment ref. This PR fixes all three. Surfaced by the audit pass on PR #60 (release). ## Changelog ### Documentation - Rewrite `docs/DESIGN.md` companion-artifacts intro to reflect the shipped (`src/styles/`, `scripts/og/`) vs research (`docs/research/design/`) split. Update all in-body path references. Research-only artifacts are referenced by name only — `docs/research/` is gated off `main`, so a link would 404 on production. ## Type of Change - [ ] `feat`: New feature (non-breaking change which adds functionality) - [ ] `fix`: Bug fix (non-breaking change which fixes an issue) - [ ] `refactor`: Code refactoring (no functional changes) - [ ] `perf`: Performance improvement - [x] `docs`: Documentation update - [ ] `test`: Adding or updating tests - [ ] `chore`: Maintenance tasks (dependencies, config, etc.) - [ ] `ci`: CI/CD configuration changes - [ ] `style`: Code style/formatting changes - [ ] `build`: Build system changes - [ ] `BREAKING CHANGE`: Breaking API change (requires major version bump) ## Related Issues/Stories - Story: PR #60 audit found stale refs surviving the #61 layout split. - Issue: n/a - Architecture: n/a (pure docs/comments). - Related PRs: #61 (the split), #60 (release — re-syncs from `dev` once this lands so the fixes ride along). ## Testing - [x] Unit tests added/updated - [x] Integration tests added/updated - [x] Manual testing completed - [x] All tests passing **Test Summary:** - Lint: biome (37 files) + markdownlint (11 files) — 0 errors. - Build: 111 pages, 97 scorecards, 96 badges, 0 orphans (unchanged). - Tests: 205 / 0 fail (unchanged). - Final grep for `docs/design` across the shipped tree: 0 hits. ## Files Modified **Modified:** - `docs/DESIGN.md` — intro rewritten + 17+ inline refs updated. - `scripts/og/og.css` — header comment block. - `tests/e2e/flows.e2e.ts` — one comment line. **Created:** - None. **Renamed:** - None. **Deleted:** - None. ## Key Features - No code or build behavior change. Pure reference cleanup. ## Deployment Notes - No runtime impact. Deploy is a no-op for `dev` (docs-only via paths-ignore). ## Reviewer Checklist - `git grep "docs/design" docs/DESIGN.md` returns nothing. - `bun run build` and `bun test` both pass (no behavioral surface touched). From 1d80b4663c9fa987d95d0c9e76052a91e8524cef Mon Sep 17 00:00:00 2001 From: Brett Date: Fri, 1 May 2026 01:58:19 -0500 Subject: [PATCH 2/9] feat(spec): vendor agentnative-spec + three-source spec-version model (#64) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Wires `agentnative-spec` into the site as a vendored snapshot, and lands a **three-source spec-version model** that fixes the v0.1.0 footer drift visible on anc.dev since the v0.1 launch. The site now has three distinct spec-version concepts because vendoring (we got a snapshot), scoring (anc was compiled against this spec), and site reconciliation (the prose has been updated to match) are three independent events that move at different cadences. Each visible-on-prod surface pulls from the source that's correct for its event: - **Footer** ← `content/principles/VERSION` (the spec version the site's prose has been reconciled to). Bumped manually by the contributor who reconciles `content/principles/p*-*.md`. Honest claim of currency — lags vendoring on purpose during the manual reconciliation window. - **Per-tool badges** ← each scorecard's own `spec_version` field (the spec the CLI was compiled against to produce that scorecard). - **OG card** ← anc's self-scorecard's `spec_version` (matches the per-tool badge convention). - **Vendored `SPEC_VERSION`** ← `src/data/spec/VERSION` (whatever `sync-spec.sh` last fetched). NOT used for any user-visible surface — kept as a reference / diff target. Implements `docs/plans/2026-04-23-001-feat-sync-spec-plan.md` U1–U4. Plan was refreshed mid-execution (commit `7afd0c4` on dev) to reflect the three-source design refinement, the v0.3.0 pin, and the dispatch-already-fires discovery from the cross-repo SYNCS-doc audit earlier in the session. ## Changelog ### Fixed - Site footer and OG card now display the actual spec version (`v0.3.0`) instead of the stale `v0.1.0` literal that shipped with the v0.1 launch. - Per-tool badge SVGs label with each scorecard's `spec_version` (the spec the CLI was compiled against for that scorecard), instead of a global default. ### Added - `./scripts/sync-spec.sh` — vendors the latest `agentnative-spec` v* tag into `src/data/spec/`. Remote-first with local checkout fallback. ## Type of Change - [x] `feat`: New feature (non-breaking change which adds functionality) - [x] `fix`: Bug fix (non-breaking change which fixes an issue) - [ ] `refactor`: Code refactoring (no functional changes) - [ ] `perf`: Performance improvement - [x] `docs`: Documentation update - [ ] `test`: Adding or updating tests - [ ] `chore`: Maintenance tasks (dependencies, config, etc.) - [ ] `ci`: CI/CD configuration changes - [ ] `style`: Code style/formatting changes - [ ] `build`: Build system changes - [ ] `BREAKING CHANGE`: Breaking API change (requires major version bump) ## Related Issues/Stories - Story: `docs/plans/2026-04-23-001-feat-sync-spec-plan.md` (refreshed on dev as commit `7afd0c4` mid-execution). - Issue: n/a - Architecture: cross-repo version model at `docs/solutions/best-practices/agentnative-version-model-2026-05-01.md` (refreshed in solutions-docs commits `bf83c71`, `47c84b2` mermaid, `7201181` three-source model). Governing pattern: `docs/solutions/best-practices/cross-repo-artifact-consumption-static-sites-2026-04-21.md`. Sibling reference impl: `~/dev/agentnative-cli/scripts/sync-spec.sh` (plan `2026-04-23-001-feat-spec-vendor-plan.md`, status: completed). - Related PRs: - `agentnative-skill` PR #11 (commit `3c3ebb6`) — deprecated SHA-pinning across the skill repo's shipping content; the site's lagging SHA-pin removal is captured as P0 todo `019-pending-p0-remove-skill-sha-pinning.md` (gitignored). - solutions-docs commit `7201181` — paired refresh of the version-model doc. ## Testing - [x] Unit tests added/updated - [x] Integration tests added/updated - [x] Manual testing completed - [x] All tests passing **Test Summary:** - Unit/regression tests: 206 passing / 0 fail / 568 expect calls (was 205 before this PR; new `tests/build.test.ts` assertion verifies footer renders `v${SITE_SPEC_VERSION}` and guards against the `v0.1.0` stub returning). - Lint: Biome (37 files clean) + markdownlint (19 files clean — adds `src/data/spec/CHANGELOG.md` to the exclusion list, since it's vendored from spec where the line-length config is more permissive). - Build: 111 HTML pages, 111 MD pages, 7 extras, 97 scorecards, 96 badge SVGs, 0 orphans. - Wrangler dry-run: 367 assets, 237 KiB upload (28 KiB gzip). - Manual: ran `./scripts/sync-spec.sh` end-to-end (remote-first path verified — vendored v0.3.0 / `5cea8bf`); ran `bun run og` — OG card regenerated showing `v0.3.0` from anc's self-scorecard; spot-checked `dist/index.html` footer renders `v0.3.0`. - Regression-test fix: `tests/regression.test.ts` test #6 (install-page dedup) now excludes `src/data/spec/` from its grep — vendored CHANGELOG legitimately mentions install commands; the test's intent was the install-page dedup, not preventing spec mentions. ## Files Modified **Modified:** - Build: `src/build/util.mjs` (adds `SITE_SPEC_VERSION` export + `readVersionFile` helper; `SPEC_VERSION` reads vendored file at module load), `src/build/shell.mjs` (footer renders `v${SITE_SPEC_VERSION}`), `src/build/build.mjs` (badge call passes `scorecard.spec_version` explicitly). - Scripts: `scripts/og/generate.ts` (reads anc's self-scorecard `spec_version`; drops the regex-from-shell.mjs hack and the `SHELL_MJS` constant entirely). - Tests: `tests/build.test.ts` (new footer-renders-vendored-version assertion), `tests/regression.test.ts` (`src/data/spec/` exclusion on regression #6). - Config: `package.json` (markdownlint exclusion for vendored `src/data/spec/CHANGELOG.md`). - Docs: `AGENTS.md` (paragraph explaining the three sources), `public/og-image.png` (regenerated; card now reads `v0.3.0`). **Created:** - `scripts/sync-spec.sh` — remote-first, latest-tag auto-pick, `git show :` extraction (no working-tree perturbation), AGENTS.md filter on principles enumeration. shellcheck-clean. - `scripts/SYNCS.md` — cross-repo sync map for this repo (was untracked from the 2026-05-01 audit; ships with this PR). Includes mermaid diagrams for the bidirectional data map and the three-source spec-version flow. - `src/data/spec/VERSION` — vendored spec version (`0.3.0`). - `src/data/spec/CHANGELOG.md` — vendored spec changelog. - `src/data/spec/principles/p1..p7.md` — vendored structured principle files (machine-readable frontmatter; diff target only, NOT consumed by site rendering). - `src/data/spec/README.md` — explains the three-version model, the manual reconciliation workflow, and the bump-`content/principles/VERSION`-LAST gate. - `content/principles/VERSION` — single-line site reconciliation marker (initial value `0.3.0`, matches current state since the site copy is reconciled to v0.3.0). **Renamed:** - None. **Deleted:** - None. ## Key Features - **Single-step spec resync**: `./scripts/sync-spec.sh` (no env vars needed in the happy path) pulls the latest `agentnative-spec` tag and rewrites `src/data/spec/`. Operator never needs a local spec checkout. - **Three-source spec-version model**: visible-on-prod surfaces stop conflating "what we vendored" with "what the site's prose has been reconciled to" with "what anc was compiled against". Each surface tells the truth about its own event. - **`content/principles/VERSION` as the reconciliation gate**: the contributor who reconciles `content/principles/p*-*.md` after a spec bump is the one who flips the footer. Bumping before reconciliation lies to visitors; the workflow now makes this explicit. - **`src/data/spec/README.md`**: explains all of the above in one place, co-located with the data it describes. ## Benefits - **Honest currency claims** on prod. Footer no longer drifts behind the spec; OG card no longer drifts behind anc. - **Reduced cognitive load** for spec releases — `./scripts/sync-spec.sh` is one command, no env vars needed in the happy path, automatic latest-tag resolution. - **Foundation for future spec-driven features**: vendored `principles/p*-*.md` is now available as a build input for future consumers (`/llms-full.txt` regen, coverage cross-refs, etc.). Not consumed yet, but the data is in-tree. ## Breaking Changes - [x] No breaking changes - [ ] Breaking changes described below: ## Deployment Notes - [x] No special deployment steps required - [ ] Deployment steps documented below: Standard pipeline: squash-merge to `dev` → `deploy.yml` publishes to the staging Worker (`agentnative-site-staging.*.workers.dev`). Promotion to `anc.dev` follows the standard `release/*` flow per RELEASES.md. After production deploy, sanity-check `curl -s https://anc.dev/ | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+'` returns `v0.3.0` (current `content/principles/VERSION`). ## Screenshots/Recordings `public/og-image.png` regenerated; the version label now reads `v0.3.0` (was `v0.1.0`). Visible inline in the diff. ## Checklist - [x] Code follows project conventions and style guidelines - [x] Commit messages follow [Conventional Commits](https://www.conventionalcommits.org/) - [x] Self-review of code completed - [x] Tests added/updated and passing - [x] No new warnings or errors introduced - [x] Changes are backward compatible (or breaking changes documented) ## Additional Context **Mid-execution design refinement.** The plan as filed scoped only U1–U3 (vendor data + docs) with footer wiring deferred. During execution, two things shifted scope: 1. The visible-on-prod `v0.1.0` footer drift made the data-vendoring useless without a consumer; U4 was promoted into scope. 2. The user proposed the three-source design (vendored ≠ reconciled ≠ scored) mid-execution, which materially improved on the original "footer reads SPEC_VERSION" approach. The plan was refreshed (dev commit `7afd0c4`) before the corresponding code landed; the SPEC_VERSION/SITE_SPEC_VERSION distinction baked itself into U4's commit (`7e5765d`). **Cross-repo coordination.** During this session's earlier SYNCS-doc audit, four sibling repos got cross-repo sync maps (3 still untracked locally per the do-not-commit directive; site's was committed via U3 here). The version-model solution doc was also added (and refreshed for the three-source model) in solutions-docs. **Skill SHA-pinning P0 todo.** Created `019-pending-p0-remove-skill-sha-pinning.md` (gitignored) capturing the follow-up work: agentnative-skill PR #11 (commit `3c3ebb6`, 2026-04-29) deprecated SHA-pinning across the skill repo's shipping content; the site is the lagging repo and still carries `source.commit` validation in `src/build/skill.mjs`. Out of scope for this PR; tracked. --- AGENTS.md | 17 ++ content/principles/VERSION | 1 + package.json | 2 +- public/og-image.png | Bin 44975 -> 44909 bytes scripts/SYNCS.md | 160 +++++++++++++++++ scripts/og/generate.ts | 39 +++-- scripts/sync-spec.sh | 128 ++++++++++++++ src/build/build.mjs | 5 +- src/build/shell.mjs | 4 +- src/build/util.mjs | 64 ++++++- src/data/spec/CHANGELOG.md | 58 +++++++ src/data/spec/README.md | 101 +++++++++++ src/data/spec/VERSION | 1 + .../p1-non-interactive-by-default.md | 130 ++++++++++++++ .../p2-structured-parseable-output.md | 124 ++++++++++++++ .../p3-progressive-help-discovery.md | 106 ++++++++++++ .../p4-fail-fast-actionable-errors.md | 141 +++++++++++++++ .../p5-safe-retries-mutation-boundaries.md | 118 +++++++++++++ ...omposable-predictable-command-structure.md | 161 ++++++++++++++++++ .../p7-bounded-high-signal-responses.md | 133 +++++++++++++++ tests/build.test.ts | 15 +- tests/regression.test.ts | 12 +- 22 files changed, 1491 insertions(+), 29 deletions(-) create mode 100644 content/principles/VERSION create mode 100644 scripts/SYNCS.md create mode 100755 scripts/sync-spec.sh create mode 100644 src/data/spec/CHANGELOG.md create mode 100644 src/data/spec/README.md create mode 100644 src/data/spec/VERSION create mode 100644 src/data/spec/principles/p1-non-interactive-by-default.md create mode 100644 src/data/spec/principles/p2-structured-parseable-output.md create mode 100644 src/data/spec/principles/p3-progressive-help-discovery.md create mode 100644 src/data/spec/principles/p4-fail-fast-actionable-errors.md create mode 100644 src/data/spec/principles/p5-safe-retries-mutation-boundaries.md create mode 100644 src/data/spec/principles/p6-composable-predictable-command-structure.md create mode 100644 src/data/spec/principles/p7-bounded-high-signal-responses.md diff --git a/AGENTS.md b/AGENTS.md index 16e8f53..7c586a8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -22,6 +22,23 @@ The scope for v0 is decided and lives in: written **manually** from these files — no build-time import, no live link. When you write or edit site copy, read the relevant `p-*.md` spec file first. Do not edit the spec to match the site; propagate in the other direction, deliberately. +- `src/data/spec/` — vendored snapshot of `brettdavies/agentnative` (the canonical spec repo) at a pinned tag. Contains + `VERSION` (the spec version this snapshot is at; exported as `SPEC_VERSION` from `src/build/util.mjs` — reference / + diff target only, NOT used for any user-visible surface), `CHANGELOG.md`, and `principles/p*-*.md` (machine-readable + frontmatter — diff target only, NOT consumed by site rendering). Refreshed via `scripts/sync-spec.sh` (remote-first; + auto-picks the latest v* tag). The site copy in `content/principles/` and the vendored spec at + `src/data/spec/principles/` coexist intentionally — they serve different audiences (humans vs machines) and their + reconciliation is a deliberate editorial act, not a derivation. +- `content/principles/VERSION` — the spec version the site's PROSE has been **reconciled to**. Exported as + `SITE_SPEC_VERSION` from `src/build/util.mjs` and rendered in the site footer. Bumped MANUALLY by the contributor who + reconciles `content/principles/p*-*.md` after a `sync-spec.sh` run — bumping before reconciliation lies to visitors + about site currency. Always ≤ `SPEC_VERSION`; lag during the manual reconciliation window is honest. The badge SVGs + use a different source (each scorecard's own `spec_version` field), and the OG card uses anc's self-scorecard's + `spec_version` — three sources for three different events (vendor / score / reconcile). +- Workflow detail in [`src/data/spec/README.md`](src/data/spec/README.md); cross-repo version model at + [`docs/solutions/best-practices/agentnative-version-model-2026-05-01.md`](docs/solutions/best-practices/agentnative-version-model-2026-05-01.md); + governing pattern at + [`docs/solutions/best-practices/cross-repo-artifact-consumption-static-sites-2026-04-21.md`](docs/solutions/best-practices/cross-repo-artifact-consumption-static-sites-2026-04-21.md). ## Thesis diff --git a/content/principles/VERSION b/content/principles/VERSION new file mode 100644 index 0000000..0d91a54 --- /dev/null +++ b/content/principles/VERSION @@ -0,0 +1 @@ +0.3.0 diff --git a/package.json b/package.json index b0d7dda..b57dec1 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "test:e2e": "playwright test", "test:e2e:docker": "bash scripts/test-e2e-docker.sh", "types": "wrangler types ./src/worker-configuration.d.ts", - "lint": "biome check . && markdownlint-cli2 \"**/*.md\" \"#node_modules\" \"#dist\" \"#docs/solutions\" \"#docs/research\" \"#docs/plans\" \"#content\" \"#CHANGELOG.md\" \"#.claude\" \"#.context\" \"#test-results\"", + "lint": "biome check . && markdownlint-cli2 \"**/*.md\" \"#node_modules\" \"#dist\" \"#docs/solutions\" \"#docs/research\" \"#docs/plans\" \"#content\" \"#CHANGELOG.md\" \"#src/data/spec/CHANGELOG.md\" \"#.claude\" \"#.context\" \"#test-results\"", "format": "biome format --write .", "deploy": "bun run build && wrangler deploy", "deploy:dryrun": "bun run build && wrangler deploy --dry-run", diff --git a/public/og-image.png b/public/og-image.png index af0904f922dc652de4de97f24ed575f1ee44b34d..5cc49f4790234633302c148309af8d8ea50ed885 100644 GIT binary patch literal 44909 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 xI6eX5ZANFSSrmpWWf1Kc0BzM%hC_K|?9Y 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 z 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 diff --git a/scripts/SYNCS.md b/scripts/SYNCS.md new file mode 100644 index 0000000..c244da0 --- /dev/null +++ b/scripts/SYNCS.md @@ -0,0 +1,160 @@ +# Cross-repo sync map + +How CLI / spec / skill data flows into this repo, and how site artifacts flow out. + +This is the source of truth for sync mechanisms — the scripts, the directions, the drift checks, and what is *planned +but not built*. Update this file whenever a sync script, workflow, endpoint, or vendored artifact changes shape. + +Existing top-level docs cover adjacent concerns but none give a single map: + +- `RELEASES.md` documents the skill-release procedure (the downstream-facing `/skill.json` re-pin) and the deploy + pipeline, but treats syncs as one step in a larger runbook. +- `docs/DESIGN.md` §3.9 / §3.10 cover the `/skill` and `/install` build contracts, not the cross-repo data flow. +- `AGENTS.md` describes endpoints and content authorship, not sync direction. + +This file gives the bidirectional view in one place. Per-script detail still lives in each script's header comment. + +## Cross-repo data map + +```mermaid +flowchart LR + subgraph In ["Inbound"] + spec[brettdavies/agentnative
spec @ pinned tag] + cliRegistry[brettdavies/agentnative-cli
coverage/matrix.json] + dockerImage[docker/score/ image
anc + scored binaries pre-installed] + end + + site[("agentnative-site
this repo")] + + subgraph Out ["Outbound"] + cliFixture[brettdavies/agentnative-cli
src/skill_install/skill.json
(SoT lives here, fixture lives there)] + cf[Cloudflare Workers
anc.dev] + agentHosts[External agents,
scorecard consumers,
badge embedders] + end + + spec -- "scripts/sync-spec.sh
(remote-first, manual)" --> site + cliRegistry -- "scripts/sync-coverage-matrix.sh
(manual)" --> site + dockerImage -- "docker/score/build.sh --run
(anc check JSON inside container)" --> site + + site -- "git pull from CLI's
sync-skill-fixture.sh" --> cliFixture + site -- "wrangler deploy
via deploy.yml" --> cf + cf -- "anc.dev endpoints
(serves the rendered site)" --> agentHosts +``` + +## Upstream — data flowing INTO this repo + +| Source | Mechanism | What's synced | Trigger / cadence | Drift check | +| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `brettdavies/agentnative-cli` `coverage/matrix.json` | `scripts/sync-coverage-matrix.sh` (manual `cp` from `$ANC_ROOT/coverage/matrix.json`) | → `src/data/coverage-matrix.json` | After CLI bumps the matrix (new checks, registry changes) | CLI's CI enforces `anc generate coverage-matrix --check` against the committed CLI artifact. Site trusts the synced copy; no site-side `--check` mode. Resync is manual; `git diff` after sync is the review surface. | +| `brettdavies/agentnative` (spec) `principles/p*-*.md` + `VERSION` + `CHANGELOG.md` | `scripts/sync-spec.sh` (manual; remote-first via `SPEC_REMOTE_URL`, falls back to local `SPEC_ROOT`; auto-picks latest v* tag; extracts via `git show "$tag:" >dest`) | → `src/data/spec/{VERSION,CHANGELOG.md,principles/p*-*.md}` (`principles/AGENTS.md` filtered out — spec-side internal) | After a spec release. Spec's `repository_dispatch:spec-release` already fires here on tag publish. | None automated on this side (consumer-side handler that auto-PRs the resync is tracked as follow-up). Spec repo's `scripts/hooks/pre-push` enforces source-side correctness. `git diff src/data/spec/` after sync is the review surface. `src/data/spec/README.md` documents the workflow. | +| `docker/score/` image — pre-installs the full ANC 100 toolset (`anc` + 96 scored binaries) inside a reproducible Ubuntu container; iterates `registry.yaml` and runs `anc check --command [--audit-profile ] --output json` for each | `bash docker/score/build.sh --run` (builds `anc` from local cli checkout, builds image, runs `score-anc100.sh` inside container with bind-mounted `scorecards/` + `out/` dirs) | → `scorecards/-v.json` (96 files) + `docker/score/out/score-failures.txt` for any install/score failures | After a new `anc` release, after registry changes, or to refresh the full leaderboard | Build-time schema 0.5 invariant validation in `src/build/scorecards.mjs`; auto-discovery picks the highest-versioned scorecard per slug, silently superseding stale ones. Filename's `-v` suffix is the version anchor (registry no longer carries `version:` per entry post-U4). The container is the source of truth — host-side ad-hoc scoring is deprecated. | + +### How spec version flows into rendering + +### How spec versions flow into rendering surfaces + +The site shows version labels in three places. **Each pulls from a different source by design** — the three sources move +at different cadences (vendoring, scoring, manual reconciliation), and conflating them into one would lie about at least +one of those movements. + +```mermaid +flowchart LR + vendoredVersion[src/data/spec/VERSION
vendored snapshot] + siteVersion[content/principles/VERSION
site reconciliation marker] + scorecardJsons[scorecards/<tool>-v<ver>.json
per-tool, embeds spec_version] + + util[src/build/util.mjs
exports SPEC_VERSION + SITE_SPEC_VERSION] + + footer[src/build/shell.mjs
footer: v${SITE_SPEC_VERSION}] + badges[src/build/build.mjs:377
renderBadgeSvg(score, scorecard.spec_version)] + og[scripts/og/generate.ts
reads anc-v*.json's spec_version] + diff[git diff workflow
operator-only — no rendered surface] + + vendoredVersion --> util + siteVersion --> util + util -- "SITE_SPEC_VERSION" --> footer + scorecardJsons -- "scorecard.spec_version" --> badges + scorecardJsons -- "anc-v*.json's spec_version" --> og + util -. "SPEC_VERSION (reference only)" .-> diff +``` + +| Surface | Source | Bumped by | +| --------------- | -------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | +| Footer | `SITE_SPEC_VERSION` ← `content/principles/VERSION` | Manual, by the contributor who reconciles `content/principles/p*-*.md` after a `sync-spec.sh` run. | +| Per-tool badges | Each scorecard's `spec_version` field | Automatic — bumps when the scorecard is regenerated against a newer `anc` build (via `docker/score/`). | +| OG card | `anc`'s self-scorecard's `spec_version` | Automatic on `bun run og` after `anc`'s scorecard is refreshed. | +| (no surface) | `SPEC_VERSION` ← `src/data/spec/VERSION` | Automatic — `./scripts/sync-spec.sh` overwrites whenever the spec ships a new tag. Reference / diff only. | + +Why three sources, not one: vendoring (we got a snapshot), scoring (anc was compiled against this spec), and site +reconciliation (the prose has been updated to match) are three independent events. Conflating them into one constant +forces at least one surface to lie about its actual currency. Full rationale in `src/data/spec/README.md` and the +cross-repo version-model doc at `docs/solutions/best-practices/agentnative-version-model-2026-05-01.md`. There is no +site-own version (`package.json` is `"0.0.0"` deliberately — the spec version IS the site's "version" by intent). + +## Downstream — data flowing OUT of this repo + +### Build-time vendoring by other repos + +| Consumer | Mechanism | What's exported | Trigger / cadence | Drift check | +| ------------------------------------------------------------ | ---------------------------------------------------------------------------------- | ----------------------------- | --------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `brettdavies/agentnative-cli` `src/skill_install/skill.json` | CLI's `scripts/sync-skill-fixture.sh` pulls from this repo's `src/data/skill.json` | Skill bundle metadata fixture | When this repo bumps `src/data/skill.json` (skill release re-pin per RELEASES.md §"Skill releases") | CLI's `skill-fixture-drift` GitHub Actions workflow runs the fixture's `--check` equivalent on every PR; CLI side fails if its vendored copy lags this repo. Effectively the inverse of the coverage-matrix arrangement: source-of-truth lives here, drift gate lives there. | + +### Deploy-time emission to Cloudflare Workers + +| Surface | Mechanism | What's emitted | Trigger / cadence | Drift check | +| ------------------------------ | ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `anc.dev` (Cloudflare Workers) | `wrangler deploy` invoked by `.github/workflows/deploy.yml` | `dist/` — HTML pages, CSS, JS, 107 per-tool scorecard HTML pages + markdown twins, 96 badge SVGs, OG image, fonts, `skill.{json,html,md}`, `install.{html,md}` (no `install.json` — see DESIGN §3.10), llms.txt, sitemap.xml | Push to `dev` (staging Worker `agentnative-site-staging`) or `main` (production `anc.dev`); `paths-ignore: docs/**, *.md` skips deploy on planning-only commits | None automated — production canary is by hand. The pre-deploy CI pipeline (`ci.yml`) gates on `bun install → lint → build → test → wrangler --dry-run`. | + +## Release / sync orchestration + +The four flows interact, but each is independently triggered: + +1. **CLI registry changes upstream** → maintainer runs `bun run scripts/sync-coverage-matrix.sh` locally → commits the + updated `src/data/coverage-matrix.json` → next site build picks up the new matrix. CLI-side CI is the integrity gate; + this repo trusts the bytes. + +2. **A scored tool ships a new version** (or `anc` itself does) → maintainer runs `bash docker/score/build.sh --run` + from the repo root → `docker/score/build.sh` rebuilds the `anc` binary from the local `agentnative-cli` checkout, + bakes it into the image, and runs `score-anc100.sh` against the full registry inside the container; bind-mounts write + the new `scorecards/-v.json` files back to the host. Old per-tool files are silently superseded by + auto-discovery → next build refreshes the badge SVG and `/score/` page. The container is the source of truth + for scoring; host-side ad-hoc scoring (the prior `regen-scorecards.sh` flow) is deprecated. + +3. **Spec cuts a new tag** → maintainer runs `bash scripts/sync-spec.sh` (auto-picks the latest v* tag from the spec + remote) → vendored `src/data/spec/{VERSION,CHANGELOG.md,principles/p*-*.md}` updates → next site build picks up the + new `SPEC_VERSION` automatically (footer, OG card, badge URLs all flow from the vendored `VERSION` file). Site + contributor reviews `git diff src/data/spec/principles/` and decides whether to manually reconcile any prose changes + into `content/principles/p*-*.md` (the two file shapes are intentionally different — see `src/data/spec/README.md` + for the workflow). Spec's `repository_dispatch:spec-release` event already fires here on tag publish; a consumer-side + handler that auto-PRs the resync is tracked as follow-up work. + +4. **Skill repo cuts a release** → maintainer fast-forwards `agentnative-skill:main` to the new tag → edits this repo's + `src/data/skill.json` (`version`, `source.commit`, `verify.expected`) → PR to `dev` → release flow to `main` → + `wrangler deploy` updates `/skill.json` on `anc.dev` → Cloudflare cache purge → CLI's next PR exercises + `skill-fixture-drift` against the new fixture. Full runbook in `RELEASES.md` §"Skill-release procedure". + +5. **Site code/content change** → push to `dev` (auto-deploys to staging Worker) → PR `dev` → `main` → push to `main` + (auto-deploys to `anc.dev`). + +## Reference + +- `scripts/sync-coverage-matrix.sh` — header comment for usage and `ANC_ROOT` env var. +- `scripts/sync-spec.sh` — header comment for usage, `SPEC_REMOTE_URL` / `SPEC_ROOT` env vars, and the + remote-first-with-local-fallback resolution flow. +- `docker/score/README.md` + `docker/score/build.sh` — the canonical scoring pipeline. `build.sh --run` builds the image + and runs `score-anc100.sh` inside the container, writing scorecards back to the host via bind mount. The container is + the single source of truth for scoring; host-side `regen-scorecards.sh` is deprecated. +- `src/data/spec/README.md` — what's vendored, why, and the manual reconciliation workflow when spec prose drifts. +- `RELEASES.md` §"Skill releases" — the downstream re-pin procedure for `src/data/skill.json` end-to-end (commit → + cache-purge → live verify). +- `docs/DESIGN.md` §3.9 (`/skill` + `/skill.json` build contract) and §3.10 (`/install` HTML-only contract). +- `AGENTS.md` — repo conventions and the `content/principles/` vs `src/data/spec/principles/` separation rule. +- `docs/plans/2026-04-23-001-feat-sync-spec-plan.md` (dev branch only, gated off main) — the plan that introduced + `sync-spec.sh` + vendored `src/data/spec/` + the SPEC_VERSION wiring. +- `docs/solutions/best-practices/agentnative-version-model-2026-05-01.md` — cross-repo version model: what version means + in each of the four agentnative repos, why the site has no own version, where each version is read or displayed. +- `docs/solutions/best-practices/cross-repo-artifact-consumption-static-sites-2026-04-21.md` — governing pattern + (commit-a-copy over build-time fetch over symlinks). +- CLI's reference implementation of `sync-spec.sh`: `~/dev/agentnative-cli/scripts/sync-spec.sh`. +- CLI's `scripts/sync-skill-fixture.sh` and `skill-fixture-drift` workflow — the inverse-direction drift gate that + protects the `src/data/skill.json` → CLI fixture flow. diff --git a/scripts/og/generate.ts b/scripts/og/generate.ts index ac7d9bc..2c38c2f 100644 --- a/scripts/og/generate.ts +++ b/scripts/og/generate.ts @@ -20,14 +20,14 @@ import { chromium } from 'playwright'; import sharp from 'sharp'; -import { readFile, writeFile } from 'node:fs/promises'; +import { readFile, readdir, writeFile } from 'node:fs/promises'; import { dirname, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; const REPO_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..'); const OG_HTML = `${REPO_ROOT}/scripts/og/og.html`; const OG_OUT = `${REPO_ROOT}/public/og-image.png`; -const SHELL_MJS = `${REPO_ROOT}/src/build/shell.mjs`; +const SCORECARDS_DIR = `${REPO_ROOT}/scorecards`; const OG_W = 1200; const OG_H = 630; @@ -35,23 +35,34 @@ const SCALE = 2; const SIZE_BUDGET_KB = 150; /** - * Read the version literal from src/build/shell.mjs. The footer ships - * a `v0.1.0` literal at line ~177 (`v0.1.0`); the OG card - * displays the same version string so the social card and the rendered - * footer never drift. When the spec-VERSION sync work lands, both will - * read from a shared source automatically. + * Read the spec_version from anc's own self-scorecard. The OG card sells + * the standard via the CLI that scores it, so the version label tracks + * what `anc` was compiled against — not what the site's content has been + * reconciled to (footer's role, see SITE_SPEC_VERSION) and not what we + * last vendored (SPEC_VERSION). Matches the per-scorecard spec_version + * each badge SVG uses (build.mjs:377). */ -async function readVersion(): Promise { - const src = await readFile(SHELL_MJS, 'utf8'); - const match = src.match(/(v\d+\.\d+\.\d+(?:[-+][\w.]+)?)<\/span>/); - if (!match) { - throw new Error(`could not find version literal in ${SHELL_MJS}`); +async function readAncSpecVersion(): Promise { + const entries = await readdir(SCORECARDS_DIR); + const ancScorecards = entries + .filter((name) => /^anc-v[\d.]+\.json$/.test(name)) + .sort() + .reverse(); // highest version first + if (ancScorecards.length === 0) { + throw new Error(`No anc scorecard found in ${SCORECARDS_DIR}/anc-v*.json`); } - return match[1]; + const sourceFile = `${SCORECARDS_DIR}/${ancScorecards[0]}`; + const json = JSON.parse(await readFile(sourceFile, 'utf8')); + if (typeof json.spec_version !== 'string') { + throw new Error(`${sourceFile} has no spec_version field`); + } + process.stderr.write(`OG version source: ${ancScorecards[0]} → spec_version=${json.spec_version}\n`); + return json.spec_version; } async function main(): Promise { - const version = await readVersion(); + const specVersion = await readAncSpecVersion(); + const version = `v${specVersion}`; process.stderr.write(`reading og.html, injecting version=${version}\n`); const browser = await chromium.launch(); diff --git a/scripts/sync-spec.sh b/scripts/sync-spec.sh new file mode 100755 index 0000000..1490af5 --- /dev/null +++ b/scripts/sync-spec.sh @@ -0,0 +1,128 @@ +#!/usr/bin/env bash +# Vendor agentnative-spec into src/data/spec/. +# +# Resolves the latest v* tag of agentnative-spec, preferring the remote +# repository, and falls back to a local checkout if the remote is +# unreachable. Extracts files via `git show :` so neither +# checkout's working tree is perturbed. The vendored tree is the build-time +# input for src/build/util.mjs (SPEC_VERSION read), which feeds the site +# footer, OG card, and badge URLs. +# +# Usage: +# scripts/sync-spec.sh +# SPEC_ROOT=/path/to/agentnative-spec scripts/sync-spec.sh +# SPEC_REMOTE_URL=git@github.com:brettdavies/agentnative.git scripts/sync-spec.sh +# +# Env vars: +# SPEC_REMOTE_URL Remote URL to query first. +# Default: https://github.com/brettdavies/agentnative.git +# SPEC_ROOT Local checkout to fall back to when the remote is +# unreachable. Default: $HOME/dev/agentnative-spec +# +# Resync cadence: rerun after every new agentnative-spec tag. The remote +# query picks up new tags automatically; a local fallback only sees what +# the local checkout already has fetched. Spec's +# `repository_dispatch:spec-release` event already fires to this repo on +# tag publish — a consumer-side handler that auto-PRs the resync is tracked +# as follow-up work. +# +# Stale orphan files in src/data/spec/principles/ (e.g., from a spec +# rename) are accepted; `git status` surfaces them at commit time. + +set -euo pipefail + +SPEC_REMOTE_URL="${SPEC_REMOTE_URL:-https://github.com/brettdavies/agentnative.git}" +SPEC_ROOT="${SPEC_ROOT:-$HOME/dev/agentnative-spec}" + +REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" +DEST_DIR="$REPO_ROOT/src/data/spec" +DEST_PRINCIPLES="$DEST_DIR/principles" + +# Cleanup hook for the temp clone (set only after mktemp succeeds). +tmp_root="" +cleanup() { + if [[ -n "$tmp_root" && -d "$tmp_root" ]]; then + rm -rf "$tmp_root" + fi +} +trap cleanup EXIT + +# === Remote-first resolution =========================================== +spec_source="" +spec_tag="" + +echo "querying $SPEC_REMOTE_URL for latest v* tag..." +remote_tag="$(git ls-remote --tags --sort='-version:refname' \ + "$SPEC_REMOTE_URL" 'refs/tags/v*' 2>/dev/null \ + | awk '{print $2}' \ + | sed 's|refs/tags/||' \ + | grep -v '\^{}$' \ + | head -n 1 || true)" + +if [[ -n "$remote_tag" ]]; then + tmp_root="$(mktemp -d -t agentnative-spec-XXXXXX)" + if git clone --depth 1 --branch "$remote_tag" --quiet \ + "$SPEC_REMOTE_URL" "$tmp_root" 2>/dev/null; then + spec_source="$tmp_root" + spec_tag="$remote_tag" + resolved_sha="$(git -C "$spec_source" rev-parse --short=7 "$spec_tag^{commit}")" + echo "vendoring $spec_tag ($resolved_sha) from remote $SPEC_REMOTE_URL" + fi +fi + +# === Local fallback ==================================================== +if [[ -z "$spec_source" ]]; then + if [[ ! -d "$SPEC_ROOT/.git" ]]; then + echo "error: remote unreachable and SPEC_ROOT is not a git repository: $SPEC_ROOT" >&2 + echo " remote: $SPEC_REMOTE_URL" >&2 + echo " set SPEC_ROOT to your agentnative-spec checkout, or check network access." >&2 + exit 1 + fi + echo "warning: remote query failed; falling back to local $SPEC_ROOT" >&2 + + spec_source="$SPEC_ROOT" + spec_tag="$(git -C "$spec_source" tag --list 'v*' --sort='-version:refname' | head -n 1)" + if [[ -z "$spec_tag" ]]; then + echo "error: no v* tags found in $SPEC_ROOT" >&2 + echo " try \`git -C $SPEC_ROOT fetch --tags\` to pick up upstream tags" >&2 + exit 1 + fi + resolved_sha="$(git -C "$spec_source" rev-parse --short=7 "$spec_tag^{commit}")" + echo "vendoring $spec_tag ($resolved_sha) from local $spec_source" +fi + +# === Verify + extract (works identically for remote and local sources) = +if ! git -C "$spec_source" cat-file -e "$spec_tag:principles" 2>/dev/null; then + echo "error: $spec_tag has no principles/ directory in $spec_source" >&2 + exit 1 +fi + +mkdir -p "$DEST_PRINCIPLES" + +# VERSION and CHANGELOG.md are top-level in the spec repo. +git -C "$spec_source" show "$spec_tag:VERSION" >"$DEST_DIR/VERSION" +git -C "$spec_source" show "$spec_tag:CHANGELOG.md" >"$DEST_DIR/CHANGELOG.md" + +# Enumerate principle files at the tag and extract each one. Filter to +# p*-*.md so principles/AGENTS.md (spec-side design context, not consumed +# by the site) is skipped. +copied=0 +while IFS= read -r path; do + case "$path" in + principles/p*-*.md) + dest_name="${path#principles/}" + git -C "$spec_source" show "$spec_tag:$path" >"$DEST_PRINCIPLES/$dest_name" + copied=$((copied + 1)) + ;; + esac +done < <(git -C "$spec_source" ls-tree --name-only "$spec_tag" principles/) + +if [[ "$copied" -eq 0 ]]; then + echo "error: no principles/p*-*.md files found at $spec_tag" >&2 + exit 1 +fi + +echo "wrote $copied principle file(s) to $DEST_PRINCIPLES" +echo "wrote VERSION + CHANGELOG.md to $DEST_DIR" +echo +echo "next: review \`git diff\` for unexpected changes, then commit." diff --git a/src/build/build.mjs b/src/build/build.mjs index 9aa1ab1..5e8ab78 100644 --- a/src/build/build.mjs +++ b/src/build/build.mjs @@ -374,7 +374,10 @@ export async function build() { // existing embed continues to render the current score after a // regression. Score derived from schema 0.5 `badge.score_pct` (0–100 // int) → 0–1 for badge-maker's color thresholds. - const svg = renderBadgeSvg(scorecard.badge.score_pct / 100); + // spec_version is per-scorecard (the spec the CLI was compiled against + // when it produced this scorecard) — pass it explicitly so the badge + // label tracks the actual scoring context, not a global default. + const svg = renderBadgeSvg(scorecard.badge.score_pct / 100, scorecard.spec_version); await writeFile(join(DIST_DIR, 'badge', `${tool.name}.svg`), svg); badgePaths.push(`/badge/${tool.name}.svg`); diff --git a/src/build/shell.mjs b/src/build/shell.mjs index 865c640..e9da185 100644 --- a/src/build/shell.mjs +++ b/src/build/shell.mjs @@ -5,7 +5,7 @@ // Inputs are plain data (no filesystem). assets.mjs reads the inline // theme-init script from disk and passes it in. -import { escHtml, resolveBaseUrl } from './util.mjs'; +import { escHtml, resolveBaseUrl, SITE_SPEC_VERSION } from './util.mjs'; const SITE_NAME = 'anc.dev'; const SITE_TAGLINE = 'The agent-native CLI standard'; @@ -187,7 +187,7 @@ ${AI_PROVIDERS.map(
Anc build
0.2.0
\` (was \`0.2.0 06a307c\`) - Audit: \`grep -c 'agentnative-cli/commit' dist/score/*.{html,md}\` returns zero across all 97 scorecard pages ## Files Modified **Modified:** - \`docker/score/Dockerfile\` — replace \`COPY\` of staged \`anc\` binary with \`brew install brettdavies/tap/agentnative\` - \`docker/score/build.sh\` — drop \`cargo build\` preamble + \`ANC_CLI_ROOT\` plumbing; collapses to image build + optional \`--run\` - \`docker/score/README.md\` — update layout, prereqs, layer order, update workflow to reflect the brew-install path - \`src/build/scorecards-render.mjs\` — \`renderAncBuildHtml\` and \`renderAncBuildMarkdown\` collapse to version-only; \`ANC_COMMIT_SHA_RE\`, \`ANC_REPO_URL\`, and the allowlist comment block removed - \`tests/build.test.ts\` — three commit-related render tests consolidate into one (\`Anc build renders version-only regardless of commit field shape\`); markdown-twin assertion drops the linked-commit form - \`content/scorecard-schema.md\` — \`anc.commit\` field row notes the field is captured but no longer surfaced **Created:** None. **Renamed:** None. **Deleted:** None. ## Key Features n/a — bug fix + docker simplification, no new features. ## Benefits - **Correctness**: scorecards no longer link to incorrect commits. - **Operator state decoupling**: docker image always uses a published release, regardless of the operator's local CLI checkout state. - **Schema-render coherence**: schema doc accurately describes what's rendered today. - **Dead-ceremony reduction**: the SHA-allowlist regex, the GitHub URL constant, and the XSS-defense test for the URL-construction path all go away alongside the path itself. ## Breaking Changes - [x] No breaking changes The \`anc.commit\` JSON-schema field stays for back-compat. Existing scorecards are not regenerated. ## Deployment Notes - [x] No special deployment steps required The next time \`bash docker/score/build.sh --run\` is invoked, scorecards will emit \`anc.commit: null\` (brewed binary has no \`.git/\` checkout, so \`build.rs\` hits the \`released-from-tarball case\`). This is expected and matches the schema-doc note added in this PR. ## Screenshots/Recordings n/a — text-only render change. The visible diff: Before: \`**Anc build:** 0.2.0 ([06a307c](https://github.com/brettdavies/agentnative-cli/commit/06a307c))\` After: \`**Anc build:** 0.2.0\` ## Checklist - [x] Code follows project conventions and style guidelines - [x] Commit messages follow [Conventional Commits](https://www.conventionalcommits.org/) - [x] Self-review of code completed - [x] Tests added/updated and passing - [x] No new warnings or errors introduced - [x] Changes are backward compatible ## Additional Context The plan for this work lives at \`docs/plans/2026-05-01-001-fix-brew-anc-strip-sha-render-plan.md\` (committed directly to \`dev\` per the planning-doc exception in \`RELEASES.md\`). --- content/scorecard-schema.md | 46 ++++++++++++++++----------------- docker/score/Dockerfile | 17 ++++++------ docker/score/README.md | 16 ++++++------ docker/score/build.sh | 39 ++++++---------------------- src/build/scorecards-render.mjs | 29 ++++----------------- tests/build.test.ts | 37 +++++++++++++------------- 6 files changed, 71 insertions(+), 113 deletions(-) diff --git a/content/scorecard-schema.md b/content/scorecard-schema.md index 41c7e90..7c1295b 100644 --- a/content/scorecard-schema.md +++ b/content/scorecard-schema.md @@ -67,10 +67,10 @@ registry. } ``` -| Field | Type | Meaning | -| --------- | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `name` | string | The literal `--command` argv passed to anc. For tools where the registry name differs from the binary (e.g., registry `ripgrep` → binary `rg`), this is the binary, not the registry slug. The filename slug owns the registry-name side of the join. | -| `binary` | string | Executable name resolved from `$PATH` at scoring time. Usually equals `tool.name` for command-mode runs. | +| Field | Type | Meaning | +| --------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `name` | string | The literal `--command` argv passed to anc. For tools where the registry name differs from the binary (e.g., registry `ripgrep` → binary `rg`), this is the binary, not the registry slug. The filename slug owns the registry-name side of the join. | +| `binary` | string | Executable name resolved from `$PATH` at scoring time. Usually equals `tool.name` for command-mode runs. | | `version` | string \| null | Best-effort version string. The CLI dumps the first line of ` --version` here without further parsing — it may carry the marketing string ("eza - A modern, maintained replacement for ls"), the full multi-line block, or `null` when the binary doesn't print anything parseable. **The filename's `` is canonical**; this field is a courtesy. | **Build-time invariant:** when `tool.version` contains a SemVer-shaped token (`X.Y` or `X.Y.Z`), it must equal the @@ -88,13 +88,13 @@ Provenance for the scorecard: which `anc` build produced it. } ``` -| Field | Type | Meaning | -| --------- | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `version` | string | Self-reported version of the `anc` binary that ran the score. Read from `Cargo.toml` at build time. | -| `commit` | string \| null | Abbreviated git SHA (7-40 hex chars) captured by `build.rs` from the working tree at compile time. `null` for `cargo install`-style builds outside a git checkout. The site links the abbreviation to the upstream commit when present. | +| Field | Type | Meaning | +| --------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `version` | string | Self-reported version of the `anc` binary that ran the score. Read from `Cargo.toml` at build time. | +| `commit` | string \| null | Abbreviated git SHA (7-40 hex chars) captured by `build.rs` from the working tree at compile time. `null` for `cargo install`-style and brew-bottle builds outside a git checkout. Captured but no longer surfaced on the rendered scorecard page; planned for removal in a future schema revision. | -The per-tool page renders `anc.version` plus an abbreviated commit link when the SHA passes the hex allowlist; non-SHA -strings fall through to a plain version with no link (security gate before URL interpolation). +The per-tool page renders `anc.version` only. The `commit` field stays in the JSON for back-compat; its removal is +deferred to a future schema revision. ## `run` @@ -109,13 +109,13 @@ Run-context: the literal invocation, when it ran, how long it took, and what pla } ``` -| Field | Type | Meaning | -| ----------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `invocation` | string | The verbatim argv that produced this scorecard, joined with single spaces. The per-tool "Reproduce locally" CTA renders this directly for command-mode runs. | -| `started_at` | string | RFC 3339 timestamp of when the run started. UTC. Validated as parseable by `Date` at build time. | -| `duration_ms` | integer | Wall-clock duration of the entire scoring run in milliseconds. | -| `platform.os` | string | OS the binary ran on (`linux`, `darwin`, `windows`). | -| `platform.arch` | string | CPU architecture the binary ran on (`x86_64`, `aarch64`, …). | +| Field | Type | Meaning | +| --------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `invocation` | string | The verbatim argv that produced this scorecard, joined with single spaces. The per-tool "Reproduce locally" CTA renders this directly for command-mode runs. | +| `started_at` | string | RFC 3339 timestamp of when the run started. UTC. Validated as parseable by `Date` at build time. | +| `duration_ms` | integer | Wall-clock duration of the entire scoring run in milliseconds. | +| `platform.os` | string | OS the binary ran on (`linux`, `darwin`, `windows`). | +| `platform.arch` | string | CPU architecture the binary ran on (`x86_64`, `aarch64`, …). | **Security note — `run.invocation`:** for command-mode runs the invocation is the canonical `anc check --command [--audit-profile ] [--output json]` shape, which is safe to embed publicly. For project-mode runs (`target.kind: @@ -135,11 +135,11 @@ What the run was scoring: a command, a binary on disk, or a project tree. } ``` -| Field | Type | Meaning | -| --------- | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Field | Type | Meaning | +| --------- | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `kind` | string | One of `command`, `binary`, or `project`. Drives whether the per-tool page's reproduce CTA renders `run.invocation` verbatim (`command`) or falls back to the synthesized form (others). Future schema-version source-layer scorecards will use `project`. | -| `path` | string \| null | Filesystem path when `kind` is `project` or `binary`; `null` for `command`-mode runs. | -| `command` | string \| null | The `--command` argv string when `kind` is `command`; `null` otherwise. For command-mode runs this equals `tool.name`. | +| `path` | string \| null | Filesystem path when `kind` is `project` or `binary`; `null` for `command`-mode runs. | +| `command` | string \| null | The `--command` argv string when `kind` is `command`; `null` otherwise. For command-mode runs this equals `tool.name`. | **Security note — `target.path`:** when `kind` is `project`, this can carry a local directory path (`/home/me/dev/foo`). It is not currently rendered on any per-tool page (every leaderboard entry today is command-mode), but downstream @@ -236,8 +236,8 @@ Array of one object per check the runner attempted. Order is stable across runs ## What is *not* in the scorecard (yet) -The site is transparent about gaps that future schema bumps may fill. Schema 0.4 closed the -tool-identity / generated-at gap (see `tool`, `anc`, `run`, `target` above). Still outstanding today: +The site is transparent about gaps that future schema bumps may fill. Schema 0.4 closed the tool-identity / generated-at +gap (see `tool`, `anc`, `run`, `target` above). Still outstanding today: - **Per-check timing** — `run.duration_ms` is the wall-clock total for the run, not per-check. Individual check timings are observable from the runner's stdout but not captured in the JSON. diff --git a/docker/score/Dockerfile b/docker/score/Dockerfile index ed5bbec..7d14db2 100644 --- a/docker/score/Dockerfile +++ b/docker/score/Dockerfile @@ -91,14 +91,15 @@ RUN --mount=type=cache,target=/home/runner/.cache/Homebrew,uid=1000,gid=1000 \ RUN --mount=type=cache,target=/home/runner/.cache/Homebrew,uid=1000,gid=1000 \ brew install yq jaq -# ---- The anc binary (glibc, built from CLI dev RC) ------------------------- -# Staged into the build context by docker/score/build.sh (which runs -# `cargo build --release` in ~/dev/agentnative-cli first, then copies the -# binary to docker/score/anc). The build context is the repo root, so the -# file path is docker/score/anc. -COPY --chown=runner:runner docker/score/anc /home/runner/.local/bin/anc -RUN chmod +x /home/runner/.local/bin/anc \ - && /home/runner/.local/bin/anc --version +# ---- The anc binary (glibc, brew-installed from the published tap) --------- +# Same install path users get on macOS / Linux. The fully-qualified +# brettdavies/tap/agentnative spec auto-taps the formula (mirrors the +# oven-sh/bun/bun pattern above). The brewed binary lives in +# /home/linuxbrew/.linuxbrew/bin and resolves to a release tag's bottle — +# no local cargo build, no operator-state coupling, no wrong-SHA risk. +RUN --mount=type=cache,target=/home/runner/.cache/Homebrew,uid=1000,gid=1000 \ + brew install brettdavies/tap/agentnative \ + && anc --version # uv tool install drops binaries in ~/.local/bin; bun add -g drops them in # ~/.bun/bin; cargo-binstall in ~/.cargo/bin. All three need to be on PATH so # the post-install `command -v ` check (in install-tools.sh) and the diff --git a/docker/score/README.md b/docker/score/README.md index eb1c9ea..35837f4 100644 --- a/docker/score/README.md +++ b/docker/score/README.md @@ -7,12 +7,11 @@ Pre-bakes every tool from `registry.yaml`, then runs `anc check` against each to ```text docker/score/ -├── Dockerfile # Debian-slim + Linuxbrew + uv + bun + cargo-binstall +├── Dockerfile # Debian-slim + Linuxbrew + uv + bun + cargo-binstall + anc ├── compose.yml # Bind-mounts + NVIDIA GPU passthrough -├── build.sh # Wrapper: build anc, build image, optionally run +├── build.sh # Wrapper: build image, optionally run ├── install-tools.sh # First-stage: install every registry tool ├── score-anc100.sh # Second-stage: iterate registry, write scorecards -├── anc # (gitignored) staged anc binary, written by build.sh ├── out/ # (gitignored) per-run logs from inside the container ├── setup-host.sh # One-time: install Docker Engine + nvidia-container-toolkit └── README.md # this file @@ -22,11 +21,12 @@ docker/score/ - **Docker Engine + Compose v2.** Engine only — NOT Docker Desktop. Install via `bash docker/score/setup-host.sh` (Ubuntu) or follow Docker's apt-repo instructions for your distro. -- **A `~/dev/agentnative-cli/` checkout** with `cargo` available. Override path with `ANC_CLI_ROOT=…`. - **For `nvidia-smi` scoring:** NVIDIA driver + `nvidia-container-toolkit` configured against the Docker daemon. The setup-host.sh script handles this if a host GPU is detected. Without it, `nvidia-smi` falls back to `install-missing` and the other 99 tools still score. +`anc` is brew-installed inside the image from `brettdavies/tap/agentnative` — no local CLI checkout required. + ## One-time host setup ```bash @@ -63,8 +63,7 @@ Layer order: 3. Linuxbrew (the heaviest single layer; cached aggressively). 4. Other package managers: `uv`, `bun`, `cargo-binstall` — all installed via brew so they're prebuilt + cached. 5. Tooling for the runner: `yq`, `jaq`. -6. The `anc` binary, copied in from the build context (built by `build.sh` from - `~/dev/agentnative-cli/target/release/anc`). +6. The `anc` binary, brew-installed from `brettdavies/tap/agentnative` (same install path users get on macOS / Linux). 7. `install-tools.sh` runs once at image build time, reading the build-time registry baked at `/build/registry.yaml` and installing every entry. Failures are logged to `/build/install-log.txt` but do NOT abort the build — tools that fail to install simply end up missing from PATH and the runner records them as `install-missing`. @@ -104,8 +103,9 @@ This image is intentionally a strict subset of the v2 sandbox image. The v2 path ## Update workflow -1. **CLI changed (new release):** rerun `bash docker/score/build.sh --run`. The `anc` binary gets rebuilt; the install - layer is cached; only scoring runs again. Faster than a full image rebuild. +1. **CLI changed (new release):** rerun `bash docker/score/build.sh --run`. The `anc` brew layer is invalidated when the + formula's pinned version moves; brew pulls the new bottle and only scoring runs again. Faster than a full image + rebuild. 2. **Registry changed (added/removed/edited a tool):** rerun the same command. The install layer is invalidated for the affected tool; brew re-resolves; scoring re-runs. 3. **Tool released a new version:** the runner's version-extract logic pulls the actually-installed version at score diff --git a/docker/score/build.sh b/docker/score/build.sh index c23d532..5777814 100755 --- a/docker/score/build.sh +++ b/docker/score/build.sh @@ -1,15 +1,13 @@ #!/usr/bin/env bash # Build the anc-scorer image and (optionally) run it. # +# `anc` is brew-installed inside the image from brettdavies/tap/agentnative +# (see Dockerfile §"The anc binary"). No local cargo build, no operator-state +# coupling — the image always uses a published release. +# # Steps: -# 1. Build the `anc` binary from the local agentnative-cli dev checkout. -# We use the dev RC because no further substantive changes to scoring -# logic are expected before v0.2.0 — only the spec re-vendor (content) -# and release ceremony. -# 2. Copy the built binary into docker/score/ so the Dockerfile build -# context can pick it up. -# 3. Build the docker image. -# 4. (Optional, with --run) Run the scorer with bind-mounts to write +# 1. Build the docker image via compose. +# 2. (Optional, with --run) Run the scorer with bind-mounts to write # scorecards back to the host. # # Usage (from repo root): @@ -19,35 +17,14 @@ set -euo pipefail REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)" -CLI_ROOT="${ANC_CLI_ROOT:-$HOME/dev/agentnative-cli}" cd "$REPO_ROOT" -if [[ ! -d "$CLI_ROOT" ]]; then - echo "error: agentnative-cli checkout not found at $CLI_ROOT" >&2 - echo " set ANC_CLI_ROOT to override" >&2 - exit 1 -fi - -# 1. Build the anc binary from CLI dev (release profile, glibc target). -echo "==> Building anc from $CLI_ROOT (release)..." -( cd "$CLI_ROOT" && cargo build --release ) -ANC_BIN="$CLI_ROOT/target/release/anc" -if [[ ! -x "$ANC_BIN" ]]; then - echo "error: expected $ANC_BIN to exist after cargo build" >&2 - exit 1 -fi -echo " built: $ANC_BIN ($("$ANC_BIN" --version))" - -# 2. Stage the binary into the build context. -cp "$ANC_BIN" "$REPO_ROOT/docker/score/anc" -chmod +x "$REPO_ROOT/docker/score/anc" - -# 3. Build the image via compose. +# 1. Build the image via compose. echo "==> Building anc-scorer image..." docker compose -f docker/score/compose.yml build -# 4. Optionally run. +# 2. Optionally run. if [[ "${1:-}" == "--run" ]]; then echo "==> Running anc-scorer..." mkdir -p docker/score/out diff --git a/src/build/scorecards-render.mjs b/src/build/scorecards-render.mjs index 2b46af2..9bb7684 100644 --- a/src/build/scorecards-render.mjs +++ b/src/build/scorecards-render.mjs @@ -28,14 +28,6 @@ function groupToPrincipleNum(group) { // out downstream site renderers as pinned consumers of this exact string. const AUDIT_PROFILE_SUPPRESSION_PREFIX = 'suppressed by audit_profile: '; -// SHA-shape allowlist for `anc.commit`. CLI v0.4 emits a 7-char abbreviation -// from build.rs; the long-form 40-char SHA is also acceptable. The regex is -// the security gate before interpolating into a GitHub commit URL — anything -// outside the hex alphabet falls through to a plain version string with no -// link, regardless of how the CLI emitted the field. -const ANC_COMMIT_SHA_RE = /^[0-9a-f]{7,40}$/; -const ANC_REPO_URL = 'https://github.com/brettdavies/agentnative-cli'; - // Format `run.duration_ms` as a human-readable interval. Granularity matches // what's useful at a glance: sub-second runs in ms, multi-second runs in // tenths, multi-minute runs in `Xm Ys`. @@ -58,28 +50,17 @@ function formatStartedAt(rfc3339) { return `${d.toISOString().replace('T', ' ').slice(0, 19)} UTC`; } -// Build an HTML fragment for the `Anc build` detail row: version + abbreviated -// commit link when the SHA passes the allowlist, version-only otherwise. +// Build an HTML fragment for the `Anc build` detail row: version-only. +// The `anc.commit` field is captured by the CLI's build.rs but no longer +// surfaced here — see content/scorecard-schema.md. function renderAncBuildHtml(anc) { if (!anc || typeof anc.version !== 'string') return null; - const versionHtml = escHtml(anc.version); - if (typeof anc.commit === 'string' && ANC_COMMIT_SHA_RE.test(anc.commit)) { - const abbrev = anc.commit.slice(0, 7); - // escHtml on the SHA defensively even after the regex check — same posture - // as the existing escHtml-everywhere convention in this module. - return `${versionHtml} ${escHtml(abbrev)}`; - } - return versionHtml; + return escHtml(anc.version); } -// Markdown twin of renderAncBuildHtml. No escHtml needed (markdown is the -// authoring layer); the SHA regex is still the security gate. +// Markdown twin of renderAncBuildHtml. function renderAncBuildMarkdown(anc) { if (!anc || typeof anc.version !== 'string') return null; - if (typeof anc.commit === 'string' && ANC_COMMIT_SHA_RE.test(anc.commit)) { - const abbrev = anc.commit.slice(0, 7); - return `${anc.version} ([${abbrev}](${ANC_REPO_URL}/commit/${anc.commit}))`; - } return anc.version; } diff --git a/tests/build.test.ts b/tests/build.test.ts index b719779..9626746 100644 --- a/tests/build.test.ts +++ b/tests/build.test.ts @@ -1948,14 +1948,16 @@ describe('buildScorecardBody — v0.4 metadata rendering', () => { expect(longRun).toContain('
Duration
2m 25s
'); }); - test('Anc build links the commit when SHA is hex-shaped (7-40 chars)', () => { - const html = buildScorecardBody(tool('rg'), sc(), [], { met: 7, total: 7, details: [] }, '15.1.0', v04Meta()); - expect(html).toContain('href="https://github.com/brettdavies/agentnative-cli/commit/fff3f13"'); - expect(html).toContain('fff3f13'); - }); - - test('Anc build skips the commit link when commit is null', () => { - const html = buildScorecardBody( + test('Anc build renders version-only regardless of commit field shape', () => { + // The commit field is captured in the JSON schema but no longer surfaced + // on the rendered scorecard. Render is version-only across hex, null, + // and malicious-string inputs alike — the field is never interpolated + // into HTML, so there is no URL-construction surface to gate. + const hex = buildScorecardBody(tool('rg'), sc(), [], { met: 7, total: 7, details: [] }, '15.1.0', v04Meta()); + expect(hex).toContain('
Anc build
0.1.0
'); + expect(hex).not.toContain('agentnative-cli/commit/'); + + const nullCommit = buildScorecardBody( tool('rg'), sc(), [], @@ -1963,13 +1965,10 @@ describe('buildScorecardBody — v0.4 metadata rendering', () => { '15.1.0', v04Meta({ anc: { version: '0.1.0', commit: null } }), ); - expect(html).toContain('
Anc build
0.1.0
'); - expect(html).not.toContain('agentnative-cli/commit/'); - }); + expect(nullCommit).toContain('
Anc build
0.1.0
'); + expect(nullCommit).not.toContain('agentnative-cli/commit/'); - test('Anc build skips the commit link when SHA fails the hex allowlist (security)', () => { - // Defense against an upstream CLI bug that ever puts non-SHA bytes into anc.commit. - const html = buildScorecardBody( + const malicious = buildScorecardBody( tool('rg'), sc(), [], @@ -1977,8 +1976,9 @@ describe('buildScorecardBody — v0.4 metadata rendering', () => { '15.1.0', v04Meta({ anc: { version: '0.1.0', commit: '' } }), ); - expect(html).not.toContain('agentnative-cli/commit/'); - expect(html).not.toContain('