@event4u/agent-config 9.6.0 → 9.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +207 -942
- package/README.md +21 -21
- package/dist/agent-src/README.md +2 -2
- package/dist/agent-src/commands/commit/in-chunks.md +8 -0
- package/dist/agent-src/commands/commit.md +17 -0
- package/dist/agent-src/commands/pr/create.md +4 -0
- package/dist/agent-src/contexts/override-system.md +75 -5
- package/dist/agent-src/rules/context-hygiene.md +2 -0
- package/dist/agent-src/rules/doc-screenshot-hygiene.md +97 -0
- package/dist/agent-src/rules/domain-safety-pii.md +1 -0
- package/dist/agent-src/rules/downstream-changes.md +31 -1
- package/dist/agent-src/rules/external-code-graph-interop.md +13 -3
- package/dist/agent-src/rules/framework-neutrality-in-generic-skills.md +2 -0
- package/dist/agent-src/rules/git-history-discipline.md +2 -0
- package/dist/agent-src/rules/language-and-tone.md +2 -0
- package/dist/agent-src/rules/lethal-trifecta-guard.md +3 -0
- package/dist/agent-src/rules/media-governance-routing.md +2 -0
- package/dist/agent-src/rules/minimal-safe-diff.md +2 -0
- package/dist/agent-src/rules/no-roadmap-references.md +3 -0
- package/dist/agent-src/rules/non-destructive-by-default.md +20 -0
- package/dist/agent-src/rules/onboarding-gate.md +2 -0
- package/dist/agent-src/rules/output-discipline.md +2 -0
- package/dist/agent-src/rules/persona-governance.md +2 -0
- package/dist/agent-src/rules/preservation-guard.md +3 -0
- package/dist/agent-src/rules/roadmap-progress-sync.md +2 -0
- package/dist/agent-src/rules/secret-vcs-guard.md +106 -0
- package/dist/agent-src/rules/security-sensitive-stop.md +1 -1
- package/dist/agent-src/rules/skill-quality.md +2 -0
- package/dist/agent-src/rules/source-confidentiality.md +2 -0
- package/dist/agent-src/rules/source-of-truth.md +2 -0
- package/dist/agent-src/rules/telegraph-speak.md +2 -0
- package/dist/agent-src/rules/token-optimizer-maintenance.md +2 -0
- package/dist/agent-src/rules/tool-safety.md +1 -0
- package/dist/agent-src/rules/verify-before-complete.md +2 -0
- package/dist/agent-src/skills/adr-create/SKILL.md +17 -1
- package/dist/agent-src/skills/agent-docs-writing/SKILL.md +34 -16
- package/dist/agent-src/skills/agents-md-thin-root/SKILL.md +9 -9
- package/dist/agent-src/skills/code-intelligence/SKILL.md +94 -0
- package/dist/agent-src/skills/gated-reach/SKILL.md +185 -0
- package/dist/agent-src/skills/gated-reach/evals/triggers.json +72 -0
- package/dist/agent-src/skills/image-analyser/SKILL.md +14 -12
- package/dist/agent-src/skills/image-editing/SKILL.md +1 -0
- package/dist/agent-src/skills/readme-writing/SKILL.md +6 -1
- package/dist/agent-src/skills/screenshot-hygiene/SKILL.md +171 -0
- package/dist/agent-src/skills/secrets-management/SKILL.md +44 -1
- package/dist/agent-src/skills/subagent-orchestration/prompts/adversarial-verification-council.md +29 -0
- package/dist/agent-src/skills/subagent-orchestration/prompts/do-and-judge-two-stage.md +29 -0
- package/dist/agent-src/skills/subagent-orchestration/prompts/do-and-judge.md +29 -0
- package/dist/agent-src/skills/subagent-orchestration/prompts/do-competitively.md +29 -0
- package/dist/agent-src/skills/subagent-orchestration/prompts/do-in-parallel.md +29 -0
- package/dist/agent-src/skills/subagent-orchestration/prompts/do-in-steps.md +29 -0
- package/dist/agent-src/skills/subagent-orchestration/prompts/do-in-worktrees.md +29 -0
- package/dist/agent-src/skills/subagent-orchestration/prompts/judge-with-debate.md +29 -0
- package/dist/agent-src/skills/verify-repair-loop/SKILL.md +4 -0
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/github-workflows/doc-impact.yml +101 -0
- package/dist/agent-src/templates/github-workflows/secret-scan.yml +65 -0
- package/dist/cli/configRoot.js +112 -0
- package/dist/cli/configRoot.js.map +1 -0
- package/dist/cli/configRoot.test.js +97 -0
- package/dist/cli/configRoot.test.js.map +1 -0
- package/dist/cli/help.js +4 -1
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/main.js +19 -2
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/registry.js +1 -0
- package/dist/cli/registry.js.map +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +164 -47
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +4 -4
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +13 -8
- package/dist/discovery/trust-report.md +11 -11
- package/dist/discovery/workspaces.json +11 -6
- package/dist/install/install.mjs +16 -0
- package/dist/mcp/awesome-mcp-servers.row.md +1 -1
- package/dist/mcp/mcp-cloudflare-catalogue.json +1 -1
- package/dist/mcp/registry-manifest.json +4 -4
- package/dist/router.json +1 -1
- package/dist/server/app.js +10 -0
- package/dist/server/app.js.map +1 -1
- package/dist/server/routes/ping.js +18 -0
- package/dist/server/routes/ping.js.map +1 -1
- package/dist/server/schemas/settings.js +8 -0
- package/dist/server/schemas/settings.js.map +1 -1
- package/dist/server/serverInfo.js +6 -2
- package/dist/server/serverInfo.js.map +1 -1
- package/dist/server/token.js +11 -4
- package/dist/server/token.js.map +1 -1
- package/dist/server/writeRoot.js +15 -1
- package/dist/server/writeRoot.js.map +1 -1
- package/dist/shared/capabilities.js +33 -0
- package/dist/shared/capabilities.js.map +1 -0
- package/dist/shared/capabilities.test.js +39 -0
- package/dist/shared/capabilities.test.js.map +1 -0
- package/dist/ui/assets/{index-BiEZiZ31.js → index-CrmZ34Rg.js} +16 -16
- package/dist/ui/assets/index-CrmZ34Rg.js.map +1 -0
- package/dist/ui/index.html +14 -5
- package/docs/CLAIMS.md +64 -38
- package/docs/architecture.md +2 -2
- package/docs/archive/CHANGELOG-6.0.0-overview.md +953 -0
- package/docs/benchmark.md +170 -9
- package/docs/catalog.md +8 -3
- package/docs/comparison.yaml +44 -2
- package/docs/contracts/local-server-ports.md +53 -0
- package/docs/contracts/no-runtime-boundary.md +1 -1
- package/docs/contracts/subagent-boundary.md +15 -0
- package/docs/customization.md +14 -3
- package/docs/decisions/ADR-016-installer-architecture.md +2 -0
- package/docs/decisions/ADR-088-no-external-runtime-federation.md +1 -1
- package/docs/decisions/ADR-094-agent-memory-layer-removal.md +1 -1
- package/docs/decisions/ADR-109-subagent-v1-contract.md +2 -0
- package/docs/decisions/ADR-110-discipline-profile-resolution-locus.md +2 -0
- package/docs/decisions/ADR-113-ci-native-release-label-trigger.md +11 -3
- package/docs/decisions/ADR-122-adversarial-verification-council.md +30 -0
- package/docs/decisions/ADR-123-runtime-security-scope-and-spawn-hardening.md +31 -0
- package/docs/decisions/ADR-124-embedded-engine-doctrine.md +255 -0
- package/docs/decisions/ADR-125-doc-screenshot-anonymization.md +131 -0
- package/docs/decisions/ADR-126-internet-reach-operator-tooling.md +254 -0
- package/docs/decisions/ADR-127-enforcement-claims-must-resolve.md +150 -0
- package/docs/decisions/ADR-128-executable-evidence-and-measured-escalation.md +201 -0
- package/docs/decisions/INDEX.md +21 -0
- package/docs/decisions/engine-reclassification-2026-07.md +104 -0
- package/docs/distribution/awesome-list-submission.md +1 -1
- package/docs/distribution/registries.md +36 -27
- package/docs/enforcement-by-host.md +7 -0
- package/docs/featured-skills.md +2 -2
- package/docs/getting-started-by-role.md +1 -1
- package/docs/getting-started.md +1 -1
- package/docs/governance-advantage.md +1 -1
- package/docs/guides/gated-platform-reads.md +221 -0
- package/docs/positioning-evidence.md +1 -1
- package/docs/proof.md +92 -16
- package/docs/spawn-site-policy.md +72 -0
- package/docs/threat-model.md +2 -1
- package/package.json +6 -3
- package/src/agent-src/README.md +2 -2
- package/src/config/agent-settings.template.yml +43 -0
- package/src/config/reach-channels.yml +217 -0
- package/src/config/reach-prescriptions-intake.yml +200 -0
- package/src/scripts/_dispatch.bash +15 -0
- package/src/scripts/_lib/adversarial_bench_score.ts +106 -0
- package/src/scripts/_lib/exec_evidence.ts +251 -0
- package/src/scripts/_lib/fixtures/secret-detector/negatives.txt +10 -0
- package/src/scripts/_lib/fixtures/secret-detector/positives.txt +11 -0
- package/src/scripts/_lib/kernel_rules.ts +46 -0
- package/src/scripts/_lib/reddit_thread_parse.ts +598 -0
- package/src/scripts/_lib/risk_paths.ts +160 -0
- package/src/scripts/_lib/secret_detector.test.ts +103 -0
- package/src/scripts/_lib/secret_detector.ts +319 -0
- package/src/scripts/_lib/spawn_env.ts +24 -4
- package/src/scripts/_lib/tool_probe.ts +359 -0
- package/src/scripts/adr/regenerate_index.ts +81 -6
- package/src/scripts/audit_adr_coverage.ts +33 -0
- package/src/scripts/bench_adversarial_council.ts +292 -0
- package/src/scripts/build_proof.ts +162 -0
- package/src/scripts/check_adr_frontmatter.ts +195 -0
- package/src/scripts/check_artefact_count_messaging.ts +4 -0
- package/src/scripts/check_backstop_debt.ts +200 -0
- package/src/scripts/check_claims.ts +188 -8
- package/src/scripts/check_comparison.ts +12 -0
- package/src/scripts/check_enforcement_coverage.ts +592 -0
- package/src/scripts/check_kernel_rule_bundle.ts +16 -12
- package/src/scripts/check_no_new_legacy_path.ts +2 -0
- package/src/scripts/check_reach_channels.ts +407 -0
- package/src/scripts/check_reach_staleness.ts +364 -0
- package/src/scripts/check_secret_leak.test.ts +47 -0
- package/src/scripts/check_secret_leak.ts +290 -0
- package/src/scripts/check_source_pointer_freshness.ts +165 -0
- package/src/scripts/code_graph/build.ts +0 -0
- package/src/scripts/code_graph/cli.ts +207 -0
- package/src/scripts/code_graph/detect.ts +134 -0
- package/src/scripts/code_graph/extract.ts +386 -0
- package/src/scripts/code_graph/loader.ts +123 -0
- package/src/scripts/code_graph/query.ts +176 -0
- package/src/scripts/code_graph/sanitize.ts +30 -0
- package/src/scripts/code_graph/types.ts +83 -0
- package/src/scripts/code_graph/validate.ts +63 -0
- package/src/scripts/external_sources_denylist.json +3 -1
- package/src/scripts/generate_subagent_floor.ts +194 -0
- package/src/scripts/hook_manifest.yaml +13 -3
- package/src/scripts/hooks/code_graph_nudge_hook.ts +184 -0
- package/src/scripts/hooks/dispatch_hook.ts +5 -1
- package/src/scripts/iron_law_sha.ts +3 -12
- package/src/scripts/lint_override_kernel_guard.ts +219 -0
- package/src/scripts/lint_readme_serial_comma.ts +169 -0
- package/src/scripts/measure_rule_budget.ts +3 -12
- package/src/scripts/postinstall_gui.ts +129 -0
- package/src/scripts/reach_doctor.ts +1651 -0
- package/src/scripts/release.ts +24 -3
- package/src/scripts/risk_escalation_shadow.ts +160 -0
- package/src/scripts/schemas/agent-settings.schema.json +23 -0
- package/src/scripts/schemas/reach-channels.schema.json +134 -0
- package/src/scripts/schemas/reach-doctor-payload.schema.json +220 -0
- package/src/scripts/schemas/rule.schema.json +10 -0
- package/src/scripts/skill_linter.ts +55 -0
- package/src/scripts/validate_reach_prescriptions.ts +751 -0
- package/src/server/schemas/settings.ts +16 -0
- package/src/shared/capabilities.test.ts +43 -0
- package/src/shared/capabilities.ts +75 -0
- package/src/templates/minimal/agents-overrides-readme.md +20 -0
- package/dist/ui/assets/index-BiEZiZ31.js.map +0 -1
|
@@ -546,6 +546,39 @@ consistency:
|
|
|
546
546
|
# reading of whichever source it happened to read).
|
|
547
547
|
cross_source: "on"
|
|
548
548
|
|
|
549
|
+
# --- Documentation screenshots ---
|
|
550
|
+
#
|
|
551
|
+
# When the agent creates screenshots for documentation (e.g. generating a docs
|
|
552
|
+
# site) and embeds them, sensitive data visible on the screenshot MUST be
|
|
553
|
+
# anonymized / pixelated before it ships. Consumed by the `doc-screenshot-hygiene`
|
|
554
|
+
# rule and the `screenshot-hygiene` skill. Automated detection is a helper that
|
|
555
|
+
# flags + pre-redacts — never a clearance; the gate for a data-bearing screenshot
|
|
556
|
+
# is human confirmation (routing into `non-destructive-by-default`, since a
|
|
557
|
+
# shipped screenshot is an irreversible published egress).
|
|
558
|
+
screenshots:
|
|
559
|
+
# Public identity tokens that are SAFE to show unredacted — the maintainer's
|
|
560
|
+
# OWN public handles (e.g. a username shown in an admin panel) plus well-known
|
|
561
|
+
# fake-data tokens. This is NOT a general fake-data dictionary and NOT
|
|
562
|
+
# identity-resolution: everything not on this list is treated as sensitive by
|
|
563
|
+
# default. A public handle co-located with a real name does NOT whitelist the
|
|
564
|
+
# real name. Default: [] (nothing auto-allowed; every identity is human-decided).
|
|
565
|
+
identity_allowlist: []
|
|
566
|
+
|
|
567
|
+
# true | false (default: true)
|
|
568
|
+
# true = terminal / CLI / IDE screenshots are FORBIDDEN (highest leak vector:
|
|
569
|
+
# absolute local paths, env tokens). Use text code blocks with text
|
|
570
|
+
# redaction instead.
|
|
571
|
+
# false = allowed, but still subject to the data-bearing human gate.
|
|
572
|
+
forbid_terminal_capture: true
|
|
573
|
+
|
|
574
|
+
# on | off (default: on)
|
|
575
|
+
# on = a data-bearing screenshot embed is gated behind this-turn human
|
|
576
|
+
# confirmation; uncertain/unresolved regions → redact-or-refuse, never
|
|
577
|
+
# ship-and-hope. Illustrative / no-data screenshots (diagrams, logos,
|
|
578
|
+
# placeholder-only UI) may embed with a stated justification.
|
|
579
|
+
# off = no data-bearing gate (legacy; the anonymization taxonomy still applies).
|
|
580
|
+
data_bearing_gate: "on"
|
|
581
|
+
|
|
549
582
|
code_style:
|
|
550
583
|
# minimal | full (default: minimal)
|
|
551
584
|
#
|
|
@@ -1007,6 +1040,16 @@ hooks:
|
|
|
1007
1040
|
design_slop:
|
|
1008
1041
|
enabled: false
|
|
1009
1042
|
|
|
1043
|
+
# PreToolUse code-graph nudge (ADR-124 Phase 4). Default-OFF. When enabled
|
|
1044
|
+
# AND a native code-graph engine has built a cache (or the repo ships a
|
|
1045
|
+
# graph.json / SCIP index), WARNS once per session (exit 2, never blocks) as
|
|
1046
|
+
# the agent is about to Grep/Glob or Read a source file: query the graph
|
|
1047
|
+
# first for "who calls / where used / impact" questions (or rebuild if the
|
|
1048
|
+
# index is stale, or build one if absent). Source G's strict block-first-read
|
|
1049
|
+
# mode is deliberately un-ported. Build the cache with `code_graph build`.
|
|
1050
|
+
code_graph:
|
|
1051
|
+
enabled: false
|
|
1052
|
+
|
|
1010
1053
|
# --- Decision engine ---
|
|
1011
1054
|
#
|
|
1012
1055
|
# Controllable gates layered over the observability surface. Absent
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# Reach channel registry — standalone operator tooling
|
|
2
|
+
# (road-to-internet-reach Phase 1).
|
|
3
|
+
#
|
|
4
|
+
# WHAT THIS FILE IS. A machine-checked answer to three operator questions:
|
|
5
|
+
# which external backend does a reach recipe need, is that backend healthy,
|
|
6
|
+
# and is its install command pinned. Schema:
|
|
7
|
+
# src/scripts/schemas/reach-channels.schema.json; gate:
|
|
8
|
+
# `task check-reach-channels`.
|
|
9
|
+
#
|
|
10
|
+
# WHAT THIS FILE IS NOT. Not a routing table, not a recommendation, not an
|
|
11
|
+
# agent-facing surface. The Phase 0 pre-registered benchmark returned
|
|
12
|
+
# `band: stop` (native arm 12/12, reach arm 0 outright wins), so no router
|
|
13
|
+
# skill ships and NO channel below is routed, preferred, or suggested to an
|
|
14
|
+
# agent. Reading a channel here as "the agent should use this" is a
|
|
15
|
+
# misreading of the verdict.
|
|
16
|
+
#
|
|
17
|
+
# BACKEND ORDER IS THE SWITCH. `backends:` is an ordered candidate list —
|
|
18
|
+
# each entry satisfies the channel on its own (an alternative, never a
|
|
19
|
+
# pipeline stage). Changing the preferred candidate is reordering this list,
|
|
20
|
+
# never editing code. Channel order carries no meaning.
|
|
21
|
+
#
|
|
22
|
+
# LIFECYCLE VOCABULARY IS BORROWED, NOT FORKED. `lifecycle:` uses the four
|
|
23
|
+
# values from docs/contracts/provider-lifecycle.md (`experimental | stable |
|
|
24
|
+
# deprecated | community`). `stable` here means the same thing it means
|
|
25
|
+
# there: a maintainer exercised it against a real run at least once.
|
|
26
|
+
#
|
|
27
|
+
# PINNING IS LOAD-BEARING. Every `install:` string is either an explicitly
|
|
28
|
+
# version-pinned command or an `os-baseline:` sentinel (see below). Moving
|
|
29
|
+
# targets — `latest`, `main`, `master`, `HEAD`, archive/tarball URLs — are
|
|
30
|
+
# rejected by the schema pattern, not by good intentions. The package never
|
|
31
|
+
# executes these strings: a human reads and runs them.
|
|
32
|
+
#
|
|
33
|
+
# OS BASELINES ARE NOT PACKAGE INSTALLS. `curl` and `node` are assumed
|
|
34
|
+
# present: they ship with the OS or the developer's base image. Their
|
|
35
|
+
# prescriptions therefore name the platform's own package manager and stay
|
|
36
|
+
# unpinned wherever a version pin is not meaningful, marked with the
|
|
37
|
+
# explicit `os-baseline:` sentinel so the absence of a pin is a declared
|
|
38
|
+
# decision rather than an oversight. Where a pin IS meaningful — Node's
|
|
39
|
+
# major line — a real versioned formula is used.
|
|
40
|
+
#
|
|
41
|
+
# `jq` IS DELIBERATELY NOT A BACKEND. JSON shaping happens inside the
|
|
42
|
+
# operator's own recipe, downstream of retrieval; it is not a candidate
|
|
43
|
+
# that satisfies a channel. If it ever becomes one, it inherits the same
|
|
44
|
+
# `os-baseline:` convention as curl.
|
|
45
|
+
#
|
|
46
|
+
# PIN PROVENANCE (looked up 2026-07-24, never invented):
|
|
47
|
+
# gh 2.96.0 — `gh --version` on the authoring machine, corroborated by
|
|
48
|
+
# https://api.github.com/repos/cli/cli/releases/latest
|
|
49
|
+
# (tag_name v2.96.0) and
|
|
50
|
+
# https://formulae.brew.sh/api/formula/gh.json (stable 2.96.0).
|
|
51
|
+
# yt-dlp 2026.7.4 — https://pypi.org/pypi/yt-dlp/json (.info.version).
|
|
52
|
+
# node@22 — https://formulae.brew.sh/api/formula/node@22.json
|
|
53
|
+
# (versioned formula exists; stable 22.23.1 at lookup time).
|
|
54
|
+
# asdf plugin `github-cli` — exists in the asdf plugin index
|
|
55
|
+
# (raw.githubusercontent.com/asdf-vm/asdf-plugins → plugins/github-cli).
|
|
56
|
+
# Homebrew has no versioned `gh` formula, so an exactly
|
|
57
|
+
# pinned macOS/Linux prescription goes through asdf.
|
|
58
|
+
# winget id `GitHub.cli` version 2.96.0 — present in the winget-pkgs manifest
|
|
59
|
+
# tree (api.github.com/repos/microsoft/winget-pkgs/contents/
|
|
60
|
+
# manifests/g/GitHub/cli lists 2.96.0).
|
|
61
|
+
#
|
|
62
|
+
# `last_verified:` MUST stay quoted — an unquoted ISO date parses as a
|
|
63
|
+
# timestamp, not a string, and fails the schema type check.
|
|
64
|
+
schema_version: reach-channels-v1
|
|
65
|
+
|
|
66
|
+
channels:
|
|
67
|
+
# Repository metadata: issues, PRs, releases, workflow runs, raw file reads.
|
|
68
|
+
# `free-key`: unauthenticated GitHub API access is rate-limited hard enough
|
|
69
|
+
# that a token is the practical floor. The token is operator-provisioned;
|
|
70
|
+
# nothing here reads, stores, or forwards it.
|
|
71
|
+
- id: github
|
|
72
|
+
description: Repository, issue, release and workflow metadata from the GitHub API.
|
|
73
|
+
tier: free-key
|
|
74
|
+
lifecycle: stable
|
|
75
|
+
override_key: reach.channels.github.backend
|
|
76
|
+
last_verified: "2026-07-24"
|
|
77
|
+
backends:
|
|
78
|
+
- id: gh
|
|
79
|
+
probe_cmd: gh
|
|
80
|
+
probe_args: ["--version"]
|
|
81
|
+
install:
|
|
82
|
+
darwin: asdf plugin add github-cli && asdf install github-cli 2.96.0
|
|
83
|
+
linux: asdf plugin add github-cli && asdf install github-cli 2.96.0
|
|
84
|
+
win32: winget install --id GitHub.cli --version 2.96.0
|
|
85
|
+
default: asdf plugin add github-cli && asdf install github-cli 2.96.0
|
|
86
|
+
|
|
87
|
+
# Video metadata and subtitle tracks. `yt-dlp` is NOT installed on the
|
|
88
|
+
# authoring machine, and that is expected: this file is validated offline
|
|
89
|
+
# against the schema only, so an absent backend cannot fail the gate. Its
|
|
90
|
+
# health is the probe layer's question, never the registry's.
|
|
91
|
+
# `experimental` for exactly that reason — the shape is right, no
|
|
92
|
+
# maintainer has exercised this backend against a real run.
|
|
93
|
+
- id: youtube
|
|
94
|
+
description: Video metadata and subtitle tracks for a public video URL.
|
|
95
|
+
tier: zero-config
|
|
96
|
+
lifecycle: experimental
|
|
97
|
+
override_key: reach.channels.youtube.backend
|
|
98
|
+
last_verified: "2026-07-24"
|
|
99
|
+
backends:
|
|
100
|
+
- id: yt-dlp
|
|
101
|
+
probe_cmd: yt-dlp
|
|
102
|
+
probe_args: ["--version"]
|
|
103
|
+
install:
|
|
104
|
+
darwin: pipx install yt-dlp==2026.7.4
|
|
105
|
+
linux: pipx install yt-dlp==2026.7.4
|
|
106
|
+
win32: py -m pipx install yt-dlp==2026.7.4
|
|
107
|
+
default: pipx install yt-dlp==2026.7.4
|
|
108
|
+
|
|
109
|
+
# Feed retrieval. Two independent candidates: fetch the feed with curl, or
|
|
110
|
+
# fetch-and-parse it in a Node one-liner. Either satisfies the channel.
|
|
111
|
+
- id: rss
|
|
112
|
+
description: Atom and RSS feed retrieval for a known feed URL.
|
|
113
|
+
tier: zero-config
|
|
114
|
+
lifecycle: stable
|
|
115
|
+
override_key: reach.channels.rss.backend
|
|
116
|
+
last_verified: "2026-07-24"
|
|
117
|
+
backends:
|
|
118
|
+
- id: curl
|
|
119
|
+
probe_cmd: curl
|
|
120
|
+
probe_args: ["--version"]
|
|
121
|
+
install:
|
|
122
|
+
darwin: "os-baseline: macOS ships curl (8.7.1 observed 2026-07-24) at /usr/bin/curl — no package install prescribed"
|
|
123
|
+
linux: "os-baseline: distro-provided curl package (apt / dnf / apk) — version tracks the distro, no pin meaningful"
|
|
124
|
+
win32: "os-baseline: Windows 10+ ships curl.exe in System32 — no package install prescribed"
|
|
125
|
+
default: "os-baseline: a system curl is assumed present; if absent, install it from the platform package manager — never a piped remote installer"
|
|
126
|
+
- id: node
|
|
127
|
+
probe_cmd: node
|
|
128
|
+
probe_args: ["--version"]
|
|
129
|
+
install:
|
|
130
|
+
darwin: brew install node@22
|
|
131
|
+
linux: "os-baseline: distro or NodeSource nodejs package — version tracks the chosen channel, no pin meaningful here"
|
|
132
|
+
win32: "os-baseline: winget package OpenJS.NodeJS.LTS — version tracks the LTS line, no pin meaningful here"
|
|
133
|
+
default: "os-baseline: any Node runtime at or above this package's engines floor (>=20.11.0) already on PATH"
|
|
134
|
+
|
|
135
|
+
# Single-page read. Same two candidates as `rss`: curl fetches the bytes;
|
|
136
|
+
# Node covers the case where the extraction step runs in-process.
|
|
137
|
+
- id: web-read
|
|
138
|
+
description: Single public web page fetch for a URL the operator already has.
|
|
139
|
+
tier: zero-config
|
|
140
|
+
lifecycle: stable
|
|
141
|
+
override_key: reach.channels.web-read.backend
|
|
142
|
+
last_verified: "2026-07-24"
|
|
143
|
+
backends:
|
|
144
|
+
- id: curl
|
|
145
|
+
probe_cmd: curl
|
|
146
|
+
probe_args: ["--version"]
|
|
147
|
+
install:
|
|
148
|
+
darwin: "os-baseline: macOS ships curl (8.7.1 observed 2026-07-24) at /usr/bin/curl — no package install prescribed"
|
|
149
|
+
linux: "os-baseline: distro-provided curl package (apt / dnf / apk) — version tracks the distro, no pin meaningful"
|
|
150
|
+
win32: "os-baseline: Windows 10+ ships curl.exe in System32 — no package install prescribed"
|
|
151
|
+
default: "os-baseline: a system curl is assumed present; if absent, install it from the platform package manager — never a piped remote installer"
|
|
152
|
+
- id: node
|
|
153
|
+
probe_cmd: node
|
|
154
|
+
probe_args: ["--version"]
|
|
155
|
+
install:
|
|
156
|
+
darwin: brew install node@22
|
|
157
|
+
linux: "os-baseline: distro or NodeSource nodejs package — version tracks the chosen channel, no pin meaningful here"
|
|
158
|
+
win32: "os-baseline: winget package OpenJS.NodeJS.LTS — version tracks the LTS line, no pin meaningful here"
|
|
159
|
+
default: "os-baseline: any Node runtime at or above this package's engines floor (>=20.11.0) already on PATH"
|
|
160
|
+
|
|
161
|
+
# Discussion search over the public Hacker News search API. Keyless, and
|
|
162
|
+
# the endpoint returns JSON directly — one candidate is enough.
|
|
163
|
+
- id: hackernews
|
|
164
|
+
description: Discussion and comment search over the public Hacker News search API.
|
|
165
|
+
tier: zero-config
|
|
166
|
+
lifecycle: stable
|
|
167
|
+
override_key: reach.channels.hackernews.backend
|
|
168
|
+
last_verified: "2026-07-24"
|
|
169
|
+
backends:
|
|
170
|
+
- id: curl
|
|
171
|
+
probe_cmd: curl
|
|
172
|
+
probe_args: ["--version"]
|
|
173
|
+
install:
|
|
174
|
+
darwin: "os-baseline: macOS ships curl (8.7.1 observed 2026-07-24) at /usr/bin/curl — no package install prescribed"
|
|
175
|
+
linux: "os-baseline: distro-provided curl package (apt / dnf / apk) — version tracks the distro, no pin meaningful"
|
|
176
|
+
win32: "os-baseline: Windows 10+ ships curl.exe in System32 — no package install prescribed"
|
|
177
|
+
default: "os-baseline: a system curl is assumed present; if absent, install it from the platform package manager — never a piped remote installer"
|
|
178
|
+
|
|
179
|
+
- id: reddit
|
|
180
|
+
description: Reddit discussion reading in two tiers — durable Atom text, and time-bounded ranked HTML.
|
|
181
|
+
tier: zero-config
|
|
182
|
+
lifecycle: experimental
|
|
183
|
+
override_key: reach.channels.reddit.backend
|
|
184
|
+
last_verified: "2026-07-25"
|
|
185
|
+
backends:
|
|
186
|
+
- id: curl
|
|
187
|
+
probe_cmd: curl
|
|
188
|
+
probe_args: ["--version"]
|
|
189
|
+
install:
|
|
190
|
+
darwin: "os-baseline: macOS ships curl (8.7.1 observed 2026-07-25) at /usr/bin/curl — no package install prescribed"
|
|
191
|
+
linux: "os-baseline: distro-provided curl package (apt / dnf / apk) — version tracks the distro, no pin meaningful"
|
|
192
|
+
win32: "os-baseline: Windows 10+ ships curl.exe in System32 — no package install prescribed"
|
|
193
|
+
default: "os-baseline: a system curl is assumed present; if absent, install it from the platform package manager — never a piped remote installer"
|
|
194
|
+
- id: node
|
|
195
|
+
probe_cmd: node
|
|
196
|
+
probe_args: ["--version"]
|
|
197
|
+
install:
|
|
198
|
+
darwin: brew install node@22
|
|
199
|
+
linux: "os-baseline: distro or NodeSource nodejs package — version tracks the chosen channel, no pin meaningful here"
|
|
200
|
+
win32: "os-baseline: winget package OpenJS.NodeJS.LTS — version tracks the LTS line, no pin meaningful here"
|
|
201
|
+
default: "os-baseline: any Node runtime at or above this package's engines floor (>=20.11.0) already on PATH"
|
|
202
|
+
|
|
203
|
+
- id: twitter-oembed
|
|
204
|
+
description: Single public tweet read through the platform's own oEmbed endpoint, credential-free.
|
|
205
|
+
tier: zero-config
|
|
206
|
+
lifecycle: experimental
|
|
207
|
+
override_key: reach.channels.twitter-oembed.backend
|
|
208
|
+
last_verified: "2026-07-25"
|
|
209
|
+
backends:
|
|
210
|
+
- id: curl
|
|
211
|
+
probe_cmd: curl
|
|
212
|
+
probe_args: ["--version"]
|
|
213
|
+
install:
|
|
214
|
+
darwin: "os-baseline: macOS ships curl (8.7.1 observed 2026-07-25) at /usr/bin/curl — no package install prescribed"
|
|
215
|
+
linux: "os-baseline: distro-provided curl package (apt / dnf / apk) — version tracks the distro, no pin meaningful"
|
|
216
|
+
win32: "os-baseline: Windows 10+ ships curl.exe in System32 — no package install prescribed"
|
|
217
|
+
default: "os-baseline: a system curl is assumed present; if absent, install it from the platform package manager — never a piped remote installer"
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# Reach prescription intake record — committed supply-chain evidence
|
|
2
|
+
# (road-to-internet-reach Phase 3, Step 2).
|
|
3
|
+
#
|
|
4
|
+
# WHAT THIS FILE IS. The offline substitute for a network lookup at lint time.
|
|
5
|
+
# `src/scripts/validate_reach_prescriptions.ts` (gate:
|
|
6
|
+
# `task check-reach-prescriptions`) reads THIS file to answer "does the package
|
|
7
|
+
# this prescription names exist, is its pin the one we checked, and was it
|
|
8
|
+
# CVE-reviewed" — it never fetches a registry. That is a hard architectural
|
|
9
|
+
# constraint, not a convenience: the Class A boundary
|
|
10
|
+
# (docs/contracts/no-runtime-boundary.md, ADR-124) forbids network access in the
|
|
11
|
+
# build path, and a lint that phones a third party is a flaky lint.
|
|
12
|
+
#
|
|
13
|
+
# CONSEQUENCE. Every claim below is a HUMAN-RUN check frozen at `checked_on`.
|
|
14
|
+
# Freshness is a maintenance duty, not a guarantee this file can make about
|
|
15
|
+
# itself: re-run the recorded commands, update `pinned_version` +
|
|
16
|
+
# `verified_on`, and change the registry pin in the same commit.
|
|
17
|
+
#
|
|
18
|
+
# WHAT AN ENTRY IS FOR. `tools:` carries exactly one entry per EXTERNALLY
|
|
19
|
+
# INSTALLED third-party tool named by an install prescription in
|
|
20
|
+
# src/config/reach-channels.yml. A prescription whose backend has no entry
|
|
21
|
+
# here cannot ship — the validator fails closed on it.
|
|
22
|
+
#
|
|
23
|
+
# WHY `os_baseline:` IS A SEPARATE CLASS, NOT A THIN `tools:` ENTRY. `curl`,
|
|
24
|
+
# `node` and `jq` are not package installs this project prescribes: they ship
|
|
25
|
+
# with the OS or the developer's base image. Writing a fake intake entry for
|
|
26
|
+
# them — "existence verified: it is curl" — would launder an assumption into
|
|
27
|
+
# evidence and put a registry/CVE claim on this project's ledger that nobody
|
|
28
|
+
# actually checked per platform. They are declared as baselines instead, with
|
|
29
|
+
# the reason, and the validator exempts them from the `tools:` requirement
|
|
30
|
+
# while still enforcing the pinning rules on any string they do carry.
|
|
31
|
+
#
|
|
32
|
+
# EXECUTION HONESTY. `asdf` and `pipx` are ABSENT on the authoring machine
|
|
33
|
+
# (`which asdf` / `which pipx` → not found), so no install command below was
|
|
34
|
+
# ever executed here. That is the design: prescription-first, human-performed,
|
|
35
|
+
# no auto-install (roadmap `## Non-goals`). Existence was verified against the
|
|
36
|
+
# registries' own metadata APIs, which is what the pin depends on.
|
|
37
|
+
#
|
|
38
|
+
# ISO DATES MUST STAY QUOTED — unquoted, YAML parses them as timestamps and
|
|
39
|
+
# the validator's string check fails loudly.
|
|
40
|
+
schema_version: reach-prescriptions-intake-v1
|
|
41
|
+
|
|
42
|
+
# The date every `verification.command` below was last executed by a human.
|
|
43
|
+
checked_on: "2026-07-24"
|
|
44
|
+
|
|
45
|
+
tools:
|
|
46
|
+
# ── gh ────────────────────────────────────────────────────────────────────
|
|
47
|
+
# Backend of the `github` channel. Two package identities because no
|
|
48
|
+
# single registry offers an exactly-pinnable `gh` on every platform:
|
|
49
|
+
# Homebrew ships only an unversioned `gh` formula (a pin there would be a
|
|
50
|
+
# lie), so macOS/Linux go through asdf, and Windows through winget.
|
|
51
|
+
- backend: gh
|
|
52
|
+
tool: gh
|
|
53
|
+
pinned_version: "2.96.0"
|
|
54
|
+
packages:
|
|
55
|
+
- registry: asdf
|
|
56
|
+
package: github-cli
|
|
57
|
+
- registry: winget
|
|
58
|
+
package: GitHub.cli
|
|
59
|
+
intake:
|
|
60
|
+
existence_verified: >-
|
|
61
|
+
Three independent confirmations at the pin. (1) The binary itself
|
|
62
|
+
reports 2.96.0 on the authoring machine. (2) The asdf plugin index
|
|
63
|
+
contains plugins/github-cli (blob sha
|
|
64
|
+
b8ab100243bc01e361a61c50d11d4ab66b790c92). (3) The winget-pkgs manifest
|
|
65
|
+
tree lists exactly 2.96.0 under manifests/g/GitHub/cli. Not a
|
|
66
|
+
model-produced name: every identifier came out of a registry response.
|
|
67
|
+
pinned: >-
|
|
68
|
+
Exact, both platforms — `asdf install github-cli 2.96.0` and
|
|
69
|
+
`winget install --id GitHub.cli --version 2.96.0`. No range, no
|
|
70
|
+
`latest`, no branch, no archive URL. Homebrew was rejected as the
|
|
71
|
+
macOS/Linux path precisely because its unversioned `gh` formula admits
|
|
72
|
+
no exact pin at all — a pinned-looking Homebrew line would be fiction.
|
|
73
|
+
lockfile_note: >-
|
|
74
|
+
No project lockfile applies — gh is an external CLI a human installs,
|
|
75
|
+
never a dependency of this package (absent from package.json, and this
|
|
76
|
+
repo ships no .tool-versions). The lock equivalent is the exact pin in
|
|
77
|
+
this record plus asdf's own .tool-versions in the operator's
|
|
78
|
+
environment, if they use one. Nothing in this repo can pin it for them.
|
|
79
|
+
cve_note: >-
|
|
80
|
+
GitHub Advisory Database, ecosystem `go`, package
|
|
81
|
+
github.com/cli/cli/v2: 6 advisories, newest first_patched_version
|
|
82
|
+
2.93.0 (GHSA-8xvp-7hj6-mcj9, TUF-mirror auth header). 2.93.0 <= 2.96.0,
|
|
83
|
+
so no listed advisory affects the pin. Reviewed by advisory listing, not
|
|
84
|
+
by a scanner — osv-scanner and pip-audit are not installed here, and
|
|
85
|
+
neither covers a system CLI install anyway.
|
|
86
|
+
verified_on: "2026-07-24"
|
|
87
|
+
verification:
|
|
88
|
+
- command: gh --version
|
|
89
|
+
source: local PATH on the authoring machine
|
|
90
|
+
observed: "gh version 2.96.0 (2026-07-02)"
|
|
91
|
+
- command: gh api repos/asdf-vm/asdf-plugins/contents/plugins/github-cli --jq '.sha + " " + .path'
|
|
92
|
+
source: https://api.github.com/repos/asdf-vm/asdf-plugins
|
|
93
|
+
observed: "b8ab100243bc01e361a61c50d11d4ab66b790c92 plugins/github-cli"
|
|
94
|
+
- command: gh api repos/microsoft/winget-pkgs/contents/manifests/g/GitHub/cli --jq '[.[].name] | map(select(startswith("2.96")))'
|
|
95
|
+
source: https://api.github.com/repos/microsoft/winget-pkgs
|
|
96
|
+
observed: '["2.96.0"]'
|
|
97
|
+
- command: gh api "/advisories?ecosystem=go&affects=github.com%2Fcli%2Fcli%2Fv2&per_page=100" --jq '[.[].vulnerabilities[] | select(.package.name=="github.com/cli/cli/v2") | .first_patched_version] | unique | sort'
|
|
98
|
+
source: https://api.github.com/advisories
|
|
99
|
+
observed: '["2.62.0","2.63.0","2.63.1","2.67.0","2.92.0","2.93.0"]'
|
|
100
|
+
|
|
101
|
+
# ── yt-dlp ────────────────────────────────────────────────────────────────
|
|
102
|
+
# Backend of the `youtube` channel, and NOT installed here — the roadmap
|
|
103
|
+
# blocker `yt-dlp-not-installed` is open by design. An intake record is
|
|
104
|
+
# about whether the prescription is safe to hand a human, which is a
|
|
105
|
+
# different question from whether the tool is present locally; the probe
|
|
106
|
+
# layer owns the second one.
|
|
107
|
+
- backend: yt-dlp
|
|
108
|
+
tool: yt-dlp
|
|
109
|
+
pinned_version: "2026.7.4"
|
|
110
|
+
packages:
|
|
111
|
+
- registry: PyPI
|
|
112
|
+
package: yt-dlp
|
|
113
|
+
intake:
|
|
114
|
+
existence_verified: >-
|
|
115
|
+
PyPI JSON API reports .info.version 2026.7.4 for the project, and the
|
|
116
|
+
per-release endpoint /pypi/yt-dlp/2026.7.4/json resolves with 2 upload
|
|
117
|
+
files — so the exact pinned release exists, not merely the project name.
|
|
118
|
+
Typo-adjacency checked deliberately: `yt-dlp` is the hyphenated form,
|
|
119
|
+
the shape most prone to hallucinated variants (`ytdlp`, `yt_dlp`,
|
|
120
|
+
`youtube-dl`); the identifier used here is the one PyPI returned.
|
|
121
|
+
pinned: >-
|
|
122
|
+
Exact PyPI equality pin — `pipx install yt-dlp==2026.7.4` (Windows:
|
|
123
|
+
`py -m pipx install yt-dlp==2026.7.4`). yt-dlp publishes date-shaped
|
|
124
|
+
versions, so a `latest`-style install would silently roll forward
|
|
125
|
+
every few days; the schema rejects that form outright.
|
|
126
|
+
lockfile_note: >-
|
|
127
|
+
No project lockfile applies — an isolated pipx application, not a
|
|
128
|
+
dependency of this package. pipx records the exact spec in its own
|
|
129
|
+
venv metadata; the pin above is the only lock this repo controls.
|
|
130
|
+
cve_note: >-
|
|
131
|
+
GitHub Advisory Database, ecosystem `pip`, package yt-dlp: 11
|
|
132
|
+
advisories, newest first_patched_version 2026.6.9 (GHSA-69qj-pvh9-c5wg
|
|
133
|
+
`--exec` command injection, plus three siblings patched in the same
|
|
134
|
+
release). 2026.6.9 < 2026.7.4, so no listed advisory affects the pin.
|
|
135
|
+
Worth carrying forward: the tool's own history is dominated by
|
|
136
|
+
argument-injection and filename-sanitization classes, which is one more
|
|
137
|
+
reason its output is untrusted content, never instructions
|
|
138
|
+
(src/rules/untrusted-input-defense.md).
|
|
139
|
+
verified_on: "2026-07-24"
|
|
140
|
+
verification:
|
|
141
|
+
- command: curl -fsSL https://pypi.org/pypi/yt-dlp/json | jq -r '.info.version'
|
|
142
|
+
source: https://pypi.org/pypi/yt-dlp/json
|
|
143
|
+
observed: "2026.7.4"
|
|
144
|
+
- command: curl -fsSL https://pypi.org/pypi/yt-dlp/2026.7.4/json | jq -r '.info.version + " files=" + (.urls|length|tostring)'
|
|
145
|
+
source: https://pypi.org/pypi/yt-dlp/2026.7.4/json
|
|
146
|
+
observed: "2026.7.4 files=2"
|
|
147
|
+
- command: gh api "/advisories?ecosystem=pip&affects=yt-dlp&per_page=100" --jq '[.[].vulnerabilities[] | select(.package.name=="yt-dlp") | .first_patched_version] | unique | sort'
|
|
148
|
+
source: https://api.github.com/advisories
|
|
149
|
+
observed: '["2023.09.24","2023.11.14","2023.7.06","2024.04.09","2024.07.01","2024.07.07","2026.02.21","2026.6.9"]'
|
|
150
|
+
|
|
151
|
+
# ── OS baselines — declared non-installs ──────────────────────────────────
|
|
152
|
+
# Present because the registry names them as backends, NOT because this
|
|
153
|
+
# project prescribes installing them. Each entry states why a pin is not
|
|
154
|
+
# meaningful; the validator exempts these from the `tools:` requirement and
|
|
155
|
+
# still enforces "pinned or explicit os-baseline sentinel" on every string
|
|
156
|
+
# they carry.
|
|
157
|
+
os_baseline:
|
|
158
|
+
- tool: curl
|
|
159
|
+
os_baseline: true
|
|
160
|
+
rationale: >-
|
|
161
|
+
Ships with macOS (/usr/bin/curl) and Windows 10+ (System32\curl.exe),
|
|
162
|
+
and is a distro package on Linux whose version tracks the distro. There
|
|
163
|
+
is no cross-platform version this project could pin without prescribing
|
|
164
|
+
a source it does not control — so the registry carries `os-baseline:`
|
|
165
|
+
sentinels and no version, deliberately.
|
|
166
|
+
verification:
|
|
167
|
+
- command: curl --version | head -1
|
|
168
|
+
source: local PATH on the authoring machine
|
|
169
|
+
observed: "curl 8.7.1 (x86_64-apple-darwin24.0) libcurl/8.7.1"
|
|
170
|
+
|
|
171
|
+
- tool: node
|
|
172
|
+
os_baseline: true
|
|
173
|
+
rationale: >-
|
|
174
|
+
A Node runtime is this package's own execution baseline
|
|
175
|
+
(package.json engines >=20.11.0), so any environment that can run the
|
|
176
|
+
validator already has it. The one platform where a pin IS meaningful —
|
|
177
|
+
Homebrew's versioned major-line formula — carries a real pin
|
|
178
|
+
(`brew install node@22`), verified below; the remaining platforms track
|
|
179
|
+
their own LTS channel and stay unpinned behind an explicit sentinel.
|
|
180
|
+
verification:
|
|
181
|
+
- command: curl -fsSL https://formulae.brew.sh/api/formula/node@22.json | jq -r '.versions.stable'
|
|
182
|
+
source: https://formulae.brew.sh/api/formula/node@22.json
|
|
183
|
+
observed: "22.23.1 (versioned formula node@22 exists)"
|
|
184
|
+
- command: node --version
|
|
185
|
+
source: local PATH on the authoring machine
|
|
186
|
+
observed: "v25.9.0"
|
|
187
|
+
|
|
188
|
+
- tool: jq
|
|
189
|
+
os_baseline: true
|
|
190
|
+
rationale: >-
|
|
191
|
+
Named nowhere in the registry as a backend on purpose — JSON shaping
|
|
192
|
+
happens inside the operator's own recipe, downstream of retrieval, so jq
|
|
193
|
+
never satisfies a channel. Recorded here so its absence from `tools:` is
|
|
194
|
+
a documented decision rather than an omission: if jq ever becomes a
|
|
195
|
+
backend it inherits curl's `os-baseline:` treatment, not a fabricated
|
|
196
|
+
pin.
|
|
197
|
+
verification:
|
|
198
|
+
- command: jq --version
|
|
199
|
+
source: local PATH on the authoring machine
|
|
200
|
+
observed: "jq-1.7.1-apple"
|
|
@@ -205,6 +205,15 @@ Tier 2 — maintenance / internal (hooks, MCP, memory, telemetry):
|
|
|
205
205
|
Usage: hooks:replay --platform <name> --event <event>
|
|
206
206
|
--payload <path|event-name> [--native-event <native>]
|
|
207
207
|
[--manifest <path>] [--json] [--dry-run]
|
|
208
|
+
reach:doctor Health report over the reach channel registry: per channel
|
|
209
|
+
the active backend, lifecycle, and the pinned install command
|
|
210
|
+
for this platform when a backend is missing/broken.
|
|
211
|
+
Read-only — no writes, no installs; NOT a router and NOT an
|
|
212
|
+
agent-facing recommendation.
|
|
213
|
+
Flags: --format json|table, --strict (CI), --channel <id>,
|
|
214
|
+
--registry <path>, --deep (⚠️ opt-in NETWORK: one real
|
|
215
|
+
read-only request per declared backend; never runs in CI,
|
|
216
|
+
writes nothing)
|
|
208
217
|
memory:lookup Retrieve memory entries (text or JSON envelope)
|
|
209
218
|
linked-projects:list List opted-in IDE-attached sibling repos (path · detected_via · large)
|
|
210
219
|
Flags: --all (show undecided too), --format json
|
|
@@ -636,6 +645,11 @@ cmd_hooks_replay() {
|
|
|
636
645
|
exec_hook "src/scripts/hooks/replay_hook" "$@"
|
|
637
646
|
}
|
|
638
647
|
|
|
648
|
+
# Read-only reach-channel health report. Never installs, never writes.
|
|
649
|
+
cmd_reach_doctor() {
|
|
650
|
+
exec_hook "src/scripts/reach_doctor" "$@"
|
|
651
|
+
}
|
|
652
|
+
|
|
639
653
|
cmd_chat_history_checkpoint() {
|
|
640
654
|
local script
|
|
641
655
|
script="$(resolve_script "src/scripts/chat_history.ts")" || return 1
|
|
@@ -1085,6 +1099,7 @@ main() {
|
|
|
1085
1099
|
hooks:status) cmd_hooks_status "$@" ;;
|
|
1086
1100
|
hooks:doctor) cmd_hooks_doctor "$@" ;;
|
|
1087
1101
|
hooks:replay) cmd_hooks_replay "$@" ;;
|
|
1102
|
+
reach:doctor) cmd_reach_doctor "$@" ;;
|
|
1088
1103
|
telemetry:record) cmd_telemetry_record "$@" ;;
|
|
1089
1104
|
telemetry:status) cmd_telemetry_status "$@" ;;
|
|
1090
1105
|
telemetry:report) cmd_telemetry_report "$@" ;;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic scorer for the adversarial-council residual-detection benchmark
|
|
3
|
+
* (road-to-adversarial-council-benchmark Phase 1).
|
|
4
|
+
*
|
|
5
|
+
* Pure + countable — never LLM-computed (the anti-lesson from ADR-122). Given a
|
|
6
|
+
* corpus item's ground truth and a reviewer's structured findings, decide
|
|
7
|
+
* whether the reviewer CAUGHT the planted defect (for a defect fixture) or
|
|
8
|
+
* raised a FALSE POSITIVE (for a clean control). The two-stage recalls and FP
|
|
9
|
+
* rates this produces feed `evaluateCouncilBench` (adversarial_council_gate.ts).
|
|
10
|
+
*
|
|
11
|
+
* Matching rule (deliberately NOT exact file:line — the scorer bug from the
|
|
12
|
+
* earlier defect-finding benchmark required an exact line token and mis-scored
|
|
13
|
+
* genuine catches that cited a nearby line): a finding CATCHES a planted defect
|
|
14
|
+
* iff it names one of the defect's file(s) by basename AND its category falls in
|
|
15
|
+
* the same normalized family as the planted defect. Line numbers are advisory,
|
|
16
|
+
* never required. This credits a real catch that localizes the right file +
|
|
17
|
+
* defect class, and denies credit for a scattershot "something's wrong here"
|
|
18
|
+
* with the wrong class.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/** Normalize a free-form category string to a coarse family. */
|
|
22
|
+
export function categoryFamily(raw: string): string {
|
|
23
|
+
const c = raw.toLowerCase().replace(/[^a-z]/g, '');
|
|
24
|
+
if (/(accesscontrol|authz|authorization|idor|bola|ownership|privilege|rbac)/.test(c)) return 'access-control';
|
|
25
|
+
if (/(auth|authentication|session|credential|login)/.test(c)) return 'auth';
|
|
26
|
+
if (/(ssrf|serverside)/.test(c)) return 'ssrf';
|
|
27
|
+
if (/(pathtraversal|traversal|directorytraversal|lfi)/.test(c)) return 'path-traversal';
|
|
28
|
+
// NB: no bare "rce" token — it substring-matches inside "resou[rce]leak".
|
|
29
|
+
if (/(injection|sqli|xss|commandinjection|deserial|remotecodeexec)/.test(c)) return 'injection';
|
|
30
|
+
if (/(crypto|cryptographic|timing|constanttime|hash|signature)/.test(c)) return 'crypto';
|
|
31
|
+
if (/(concurrency|race|atomic|deadlock|idempoten)/.test(c)) return 'concurrency';
|
|
32
|
+
if (/(resourceleak|leak|memory|handle|unsubscrib|cleanup)/.test(c)) return 'resource-leak';
|
|
33
|
+
if (/(dataintegrity|integrity|corrupt|consistency|stale)/.test(c)) return 'data-integrity';
|
|
34
|
+
if (/(correctness|logic|offbyone|boundary|edgecase|bug)/.test(c)) return 'correctness';
|
|
35
|
+
return 'other';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface Finding {
|
|
39
|
+
/** File the finding points at (any path form; matched by basename). */
|
|
40
|
+
file: string;
|
|
41
|
+
/** Reviewer-supplied category (free text; normalized via categoryFamily). */
|
|
42
|
+
category: string;
|
|
43
|
+
/** Reviewer confidence, if given. Low-confidence findings can be excluded from FP counting. */
|
|
44
|
+
confidence?: 'high' | 'medium' | 'low';
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface GroundTruth {
|
|
48
|
+
id: string;
|
|
49
|
+
/** true = clean control (no defect); a finding here is a false positive. */
|
|
50
|
+
is_clean: boolean;
|
|
51
|
+
/** Basenames of the file(s) the planted defect lives in (empty for clean). */
|
|
52
|
+
defect_files: string[];
|
|
53
|
+
/** Planted defect category family (via categoryFamily); empty for clean. */
|
|
54
|
+
defect_category: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function basename(p: string): string {
|
|
58
|
+
return p.split(/[\\/]/).pop() ?? p;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Did the reviewer CATCH the planted defect? file-basename match on any defect
|
|
63
|
+
* file AND category-family match. Clean controls always return false (they have
|
|
64
|
+
* no defect to catch — use `isFalsePositive` for them).
|
|
65
|
+
*/
|
|
66
|
+
export function caughtDefect(truth: GroundTruth, findings: Finding[]): boolean {
|
|
67
|
+
if (truth.is_clean) return false;
|
|
68
|
+
const wantFiles = new Set(truth.defect_files.map(basename));
|
|
69
|
+
const wantFamily = truth.defect_category;
|
|
70
|
+
return findings.some(
|
|
71
|
+
(f) => wantFiles.has(basename(f.file)) && categoryFamily(f.category) === wantFamily,
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Did the reviewer raise a FALSE POSITIVE on a clean control? Any finding that
|
|
77
|
+
* points at the control file counts (a claimed defect where none exists).
|
|
78
|
+
* Low-confidence findings are excluded — a hedged "might check X" is not a FP
|
|
79
|
+
* claim. Non-clean fixtures always return false.
|
|
80
|
+
*/
|
|
81
|
+
export function isFalsePositive(truth: GroundTruth, findings: Finding[]): boolean {
|
|
82
|
+
if (!truth.is_clean) return false;
|
|
83
|
+
return findings.some((f) => (f.confidence ?? 'high') !== 'low');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface StageResult {
|
|
87
|
+
/** Per-defect-fixture: id → caught?. Excludes clean controls. */
|
|
88
|
+
caught: Record<string, boolean>;
|
|
89
|
+
/** Per-clean-control: id → false-positive?. */
|
|
90
|
+
fp: Record<string, boolean>;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Recall over a set of defect ids, given per-id caught flags. */
|
|
94
|
+
export function recall(caught: Record<string, boolean>): number {
|
|
95
|
+
const ids = Object.keys(caught);
|
|
96
|
+
if (ids.length === 0) return 0;
|
|
97
|
+
const hits = ids.filter((id) => caught[id]).length;
|
|
98
|
+
return hits / ids.length;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** FP rate over clean controls. */
|
|
102
|
+
export function fpRate(fp: Record<string, boolean>): number {
|
|
103
|
+
const ids = Object.keys(fp);
|
|
104
|
+
if (ids.length === 0) return 0;
|
|
105
|
+
return ids.filter((id) => fp[id]).length / ids.length;
|
|
106
|
+
}
|