@event4u/agent-config 9.7.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 +144 -0
- package/README.md +5 -5
- 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/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/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/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 +161 -44
- 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/registry-manifest.json +3 -3
- 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 +62 -37
- package/docs/architecture.md +2 -2
- package/docs/benchmark.md +137 -0
- 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-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/threat-model.md +1 -0
- package/package.json +5 -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/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/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/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_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/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/iron_law_sha.ts +3 -12
- package/src/scripts/lint_override_kernel_guard.ts +219 -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
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
---
|
|
2
|
+
adr: 126
|
|
3
|
+
status: accepted
|
|
4
|
+
date: 2026-07-24
|
|
5
|
+
decision: internet-reach-operator-tooling
|
|
6
|
+
supersedes: —
|
|
7
|
+
superseded_by: —
|
|
8
|
+
phase: road-to-internet-reach
|
|
9
|
+
type: structural
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# ADR-126 — Internet reach: operator tooling shipped, router skill cancelled by its own gate
|
|
13
|
+
|
|
14
|
+
- **Status:** Accepted (2026-07-24)
|
|
15
|
+
- **Closes:** `agents/roadmaps/archive/road-to-internet-reach.md`
|
|
16
|
+
- **Related:** `docs/contracts/no-runtime-boundary.md` (Class A boundary); ADR-112 (read-only command discipline); ADR-123 (hardened spawn env); ADR-124 (embedded-engine doctrine / Class A–C); `src/rules/lethal-trifecta-guard.md`; `src/rules/source-confidentiality.md`; `src/skills/supply-chain-intake/SKILL.md`; `docs/benchmark.md` § internet-reach.
|
|
17
|
+
|
|
18
|
+
## Context
|
|
19
|
+
|
|
20
|
+
The package had no coverage for internet reach: no web-research router, no
|
|
21
|
+
upstream-tool health check, no platform-access prescriptions. `CAPABILITIES.yaml`
|
|
22
|
+
listed 279 skills across 28 areas with `gaps: 0` — true for the areas the index
|
|
23
|
+
tracks, and internet reach was not one of them.
|
|
24
|
+
|
|
25
|
+
An external capability-layer reference (anonymized per `source-confidentiality`;
|
|
26
|
+
provenance retained as an `ENC1:` token in the roadmap) solves this with four
|
|
27
|
+
jobs — backend selection, installation, health checking, routing — while
|
|
28
|
+
explicitly not wrapping the upstream tools. Three of its mechanism shapes were
|
|
29
|
+
worth absorbing: ordered-backend channels (switching a backend is reordering a
|
|
30
|
+
list, not editing code), a five-state probe taxonomy with stale-shim detection,
|
|
31
|
+
and a tiered access model. Four of its practices were rejected outright:
|
|
32
|
+
auto-installation from an unpinned archive, browser-credential harvesting,
|
|
33
|
+
an agent-obligating update-check standing rule, and a "MUST USE" trigger with no
|
|
34
|
+
published evidence.
|
|
35
|
+
|
|
36
|
+
The open question was **not** whether those mechanisms are implementable — they
|
|
37
|
+
plainly are — but whether a reach layer earns its place next to the host's own
|
|
38
|
+
web-search and web-fetch tools. That question was made falsifiable before any
|
|
39
|
+
tracked code existed.
|
|
40
|
+
|
|
41
|
+
## Decision
|
|
42
|
+
|
|
43
|
+
**1. The reach layer is Class A.** Deterministic, command-invoked probe /
|
|
44
|
+
doctor / validation scripts. No LLM call and no network access in the build
|
|
45
|
+
path, no resident process, no daemon, no wrapper CLI, no MCP reach server.
|
|
46
|
+
Reading and searching itself stays "the agent calls the upstream tool directly".
|
|
47
|
+
Every subprocess spawn routes through `hardenedSpawnEnv()` (ADR-123).
|
|
48
|
+
|
|
49
|
+
**2. Scope was decided by a pre-registered benchmark, before authoring.** 12
|
|
50
|
+
credential-free dev-research tasks × 2 arms (host-native tools vs. prototype
|
|
51
|
+
reach prescriptions), thresholds and three verdict bands committed before the
|
|
52
|
+
run, prescriptions prototyped in gitignored scratch first so both arms were real
|
|
53
|
+
at scoring time.
|
|
54
|
+
|
|
55
|
+
**3. The benchmark returned a null, and the null was honoured.** The native arm
|
|
56
|
+
passed 12/12; the reach arm scored **0 outright wins of 12** under the
|
|
57
|
+
pre-registered rule (reach wins only where native fails; ties are native wins) →
|
|
58
|
+
band `stop`. Therefore **no router skill ships.** The `internet-reach` skill,
|
|
59
|
+
its gated-platform prescription set, and the shipped-skill verdict run were
|
|
60
|
+
cancelled *pre-authoring* by the gate that was built to cancel them.
|
|
61
|
+
|
|
62
|
+
**4. The verdict-independent operator tooling ships anyway,** because it answers
|
|
63
|
+
a question that does not need a router: *is the upstream tool I already chose to
|
|
64
|
+
install healthy, and is its install command pinned?* Concretely: a
|
|
65
|
+
schema-validated channel registry, a five-state probe engine with stale-shim
|
|
66
|
+
detection, a read-only `reach:doctor`, and a CI gate that fails on any unpinned
|
|
67
|
+
install prescription.
|
|
68
|
+
|
|
69
|
+
**5. Supply chain is prescription-first, mechanized.** No automatic installation
|
|
70
|
+
of system packages, no piping a remote script into a shell. The doctor emits an
|
|
71
|
+
exact pinned command; a human runs it. "Every prescription passes the intake
|
|
72
|
+
gate" is enforced by `check_reach_channels` + `validate_reach_prescriptions` in
|
|
73
|
+
CI, not by an honour system — the failure mode the reference itself exhibits.
|
|
74
|
+
|
|
75
|
+
**6. Two capabilities are refused, not deferred-with-a-wink.** Browser-credential
|
|
76
|
+
extraction (a lethal-trifecta leg; the reference documents the account-ban risk
|
|
77
|
+
it creates) and CN-market channels (perpetual anti-bot maintenance, no demand
|
|
78
|
+
signal in this audience). Re-opening either requires a named demand signal and
|
|
79
|
+
its own roadmap.
|
|
80
|
+
|
|
81
|
+
**7. An adversarial security review ran pre-merge and found a real HIGH — it was
|
|
82
|
+
fixed, not documented-around.** The review (`agent-security-review` +
|
|
83
|
+
`threat-modeling` over the five reach scripts, the two schemas and the
|
|
84
|
+
registration) confirmed the design's strongest property: neither spawn site uses
|
|
85
|
+
a shell, no reach script contains a write primitive, no fetched byte reaches any
|
|
86
|
+
payload (both spawns discard stdout/stderr, so the only network-derived datum is
|
|
87
|
+
an exit code), the credential check stats and never reads, and all three gates are
|
|
88
|
+
fail-closed (13/13 negative fixtures non-zero, controls zero). It also found that
|
|
89
|
+
`reach:doctor` never validated the registry at runtime while the schema's
|
|
90
|
+
`probe_args` denylist leaked — a registry entry of `probe_cmd: sh` +
|
|
91
|
+
`probe_args: ["-c", "<payload>"]` passed all three gates with ✅ and was then
|
|
92
|
+
executed and reported as healthy under the innocuous backend label. The false
|
|
93
|
+
assurance was the defect: the schema asserted a probe "can never install, write,
|
|
94
|
+
or authenticate as a side effect", and that was not true. Fixed in the same
|
|
95
|
+
change: `collect()` now enforces the schema and refuses on any error-severity
|
|
96
|
+
finding (exit 2), `probe_args` became a flag-shaped **allowlist**, `probe_cmd` is
|
|
97
|
+
bound to equal its backend `id` (so a row can never label a different binary), the
|
|
98
|
+
prototype-chain lookup on the deep-probe table is guarded, the CI refusal moved
|
|
99
|
+
from the CLI layer into `collect()`, parse errors no longer echo file content, and
|
|
100
|
+
the read-only witness assertion was narrowed to what it actually measures. Two
|
|
101
|
+
permanent regression fixtures cover the hostile-registry shape. The schema comment
|
|
102
|
+
now states a bounded claim and explicitly declines to promise that every upstream
|
|
103
|
+
binary is side-effect-free under every flag — that judgement stays with the human
|
|
104
|
+
adding a backend.
|
|
105
|
+
|
|
106
|
+
**A second review round — an external bot gate plus a paid multi-model council —
|
|
107
|
+
found one more real primitive, and two of its HIGHs did not reproduce.** Recorded
|
|
108
|
+
because a review trail that only lists confirmed hits teaches the wrong lesson
|
|
109
|
+
about review. The bot gate's two HIGH findings were probed before being believed
|
|
110
|
+
and **neither reproduced as worded**: the deep-probe table was already
|
|
111
|
+
`Object.hasOwn`-guarded behind a `collect()` gate that validates before any load
|
|
112
|
+
or spawn, and a nine-way probe matrix over every entry point showed the parse
|
|
113
|
+
paths leaked nothing. Its `removal_after`-compared-lexicographically finding was a
|
|
114
|
+
false positive twice over (the code parses to epoch numbers, and the schema pins
|
|
115
|
+
both date fields to a fixed-width ISO pattern). Each is now documented at the site
|
|
116
|
+
so it cannot be re-raised without reading the refutation. What the round DID find:
|
|
117
|
+
(a) the grep gate echoed matched file lines verbatim, so `--registry <any file>`
|
|
118
|
+
printed that file's content back — closed at all **four** echo sites, the fourth
|
|
119
|
+
found only by re-running the probe against every entry point instead of assuming
|
|
120
|
+
three fixes had closed the class; and (b) via the council, `credential_path` was
|
|
121
|
+
an arbitrary-path oracle — a registry declaring
|
|
122
|
+
`credential_path: ../../../../etc/passwd` made the doctor report that path's
|
|
123
|
+
existence and permissions at exit 0 inside a normal-looking health row. Now
|
|
124
|
+
confined to the operator's home, this repo, or the temp dir, checked against both
|
|
125
|
+
the literal and realpath'd form of each (so a symlink cannot escape), refused
|
|
126
|
+
before any syscall, and reported as a refusal rather than a silent skip. Both fixes
|
|
127
|
+
are mutation-tested: forcing the confinement open turns six tests red, and deleting
|
|
128
|
+
the file-type check turns the directory case red.
|
|
129
|
+
|
|
130
|
+
## Consequences
|
|
131
|
+
|
|
132
|
+
**Good.**
|
|
133
|
+
|
|
134
|
+
- The most expensive possible mistake — authoring, projecting, indexing and
|
|
135
|
+
publicly claiming a router skill that loses to tools the user already has —
|
|
136
|
+
was avoided by measurement rather than by taste.
|
|
137
|
+
- What shipped is small, deterministic and independently useful; it carries no
|
|
138
|
+
availability promise and no SLA.
|
|
139
|
+
- A published null strengthens the package's evidence posture: the benchmark
|
|
140
|
+
surface now contains a case where the package's own proposed feature lost.
|
|
141
|
+
- Pinning and lifecycle discipline are machine-checked, so the supply-chain
|
|
142
|
+
claim is falsifiable rather than aspirational.
|
|
143
|
+
|
|
144
|
+
**Bad / accepted costs.**
|
|
145
|
+
|
|
146
|
+
- The capability gap for **gated platforms stays open.** The credential-free
|
|
147
|
+
task set (needed for reproducibility) structurally excluded the two cases
|
|
148
|
+
where a reach advantage was hypothesized: video subtitles (backend absent →
|
|
149
|
+
`untested`) and authenticated / rate-limited access. The null is therefore
|
|
150
|
+
narrow: *on public, credential-free dev-research tasks*, a reach layer buys no
|
|
151
|
+
capability the host lacks. Anyone wanting the gated case measured must
|
|
152
|
+
pre-register a credentialed task set with its own thresholds.
|
|
153
|
+
- A **measured cost asymmetry is left on the table on purpose.** On all 8 tasks
|
|
154
|
+
both arms solved, the reach arm cost 0.46× the native arm's tokens (0.26× on
|
|
155
|
+
repository metadata, 0.31× on discussion search) — the native arm repeatedly
|
|
156
|
+
paid *discovery overhead* to find the machine-readable endpoint the
|
|
157
|
+
prescription already knows. This is recorded outside the decision: the token
|
|
158
|
+
threshold was authored as a ≤1.5× guardrail, never a win condition, and
|
|
159
|
+
promoting it to one after seeing the data would be precisely the post-hoc
|
|
160
|
+
rigging the bands exist to prevent. Acting on it requires a separate,
|
|
161
|
+
cost-primary pre-registration.
|
|
162
|
+
- **Both accepted costs now have a named re-entry point,** so neither stays a
|
|
163
|
+
footnote: the credential-gated case the keyless task set could not ask, and the
|
|
164
|
+
cost thesis (whose pre-registration must make token cost the primary metric and
|
|
165
|
+
must price the maintenance cost of the thing winning). Both are parked as
|
|
166
|
+
named plans in the roadmap layer with explicit resume triggers — a named demand
|
|
167
|
+
signal, a measured host-capability regression, or a maintainer decision. Paths
|
|
168
|
+
are deliberately not cited here: the roadmap layer is transient and a stable
|
|
169
|
+
artefact must not link into it (`no-roadmap-references`). The gated-platform one
|
|
170
|
+
has since fired and been executed — see § Amendment 2026-07-25. Neither may reuse this
|
|
171
|
+
roadmap's task set or thresholds: a capability-shaped corpus must not be
|
|
172
|
+
allowed to decide a cost question, and vice versa.
|
|
173
|
+
- The registry carries maintenance weight (upstream tools break at platform
|
|
174
|
+
cadence). Contained by `last_verified` + an offline staleness lint + an
|
|
175
|
+
append-only upstream-change log — not by a scheduled network job, which would
|
|
176
|
+
buy flaky CI and an implicit availability promise.
|
|
177
|
+
|
|
178
|
+
## Alternatives considered
|
|
179
|
+
|
|
180
|
+
- **Ship the router anyway and measure later.** Rejected: re-benchmarking an
|
|
181
|
+
already merged, indexed and comparison-table-listed skill documents a decision
|
|
182
|
+
instead of gating it. The gate has to be able to say no.
|
|
183
|
+
- **Lower the win threshold until the reach arm passes.** Rejected as rigging.
|
|
184
|
+
Worth recording that the band is *defect-insensitive* here: two reach failures
|
|
185
|
+
were prescription bugs, but repairing them yields ties, and ties are native
|
|
186
|
+
wins — zero native failures means zero possible reach wins regardless of
|
|
187
|
+
prescription quality. There was nothing to salvage by re-running.
|
|
188
|
+
- **Promote the token-cost finding into the verdict.** Rejected for this
|
|
189
|
+
roadmap; see the accepted cost above. It is a genuine signal and it deserves
|
|
190
|
+
its own honest experiment, not a retrofitted one.
|
|
191
|
+
- **A weekly scheduled job probing every upstream backend.** Rejected: flaky CI
|
|
192
|
+
against third-party endpoints plus an availability promise the package does
|
|
193
|
+
not make. Replaced by staleness metadata + an operator-invoked deep check.
|
|
194
|
+
- **A credits/attribution entry naming the reference.** Rejected:
|
|
195
|
+
`source-confidentiality` forbids derivation-attribution in tracked artefacts,
|
|
196
|
+
and the license carve-out covers vendored code only — nothing is vendored.
|
|
197
|
+
Provenance lives anonymized in the roadmap with the link as an `ENC1:` token,
|
|
198
|
+
and the reference's identifying tokens were added to the CI denylist so a
|
|
199
|
+
future accidental attribution fails the build.
|
|
200
|
+
|
|
201
|
+
## Amendment 2026-07-25 — the gated-platform gap, measured and partly closed
|
|
202
|
+
|
|
203
|
+
This ADR's null was scoped explicitly: *"It says nothing about gated-platform
|
|
204
|
+
access. Testing that needs a credentialed task set with its own
|
|
205
|
+
pre-registration."* That test has now run, and the first thing it found is that
|
|
206
|
+
the sentence's premise was wrong — **no credentials were needed**.
|
|
207
|
+
|
|
208
|
+
**Closed for three channels, credential-free.** Reddit thread text (Atom feeds),
|
|
209
|
+
Reddit comment **ranking and reply nesting** (server-rendered HTML), and a single
|
|
210
|
+
named tweet (the platform's own oEmbed endpoint) all reached 6/6 against a
|
|
211
|
+
pre-registered task set with a native control and thresholds frozen before the
|
|
212
|
+
run. The native arm scored 0/6 on both Reddit tiers, because the host's own tool
|
|
213
|
+
refuses the `reddit.com` domain outright. Evidence: `docs/benchmark.md`
|
|
214
|
+
§ gated-reach; `internal/bench/gated-reach/{README,results,VERDICT}.md`.
|
|
215
|
+
|
|
216
|
+
**Still open, each with its re-entry trigger.**
|
|
217
|
+
|
|
218
|
+
| Surface | State | Re-entry trigger |
|
|
219
|
+
|---|---|---|
|
|
220
|
+
| YouTube transcripts | **parked, unexercised** | the backend is installed by a human and one real extraction is run |
|
|
221
|
+
| Reddit logged-in HTML (session cookie) | parked | an observed login wall on `old.reddit` **and** the maintainer choosing that successor |
|
|
222
|
+
| Reddit approved Data API | parked | the maintainer choosing the durable path — approval-only, weeks of latency, so it starts before it is needed or not at all |
|
|
223
|
+
| Twitter timelines / search | parked | a task that genuinely needs them; no credential-free path exists |
|
|
224
|
+
| Headless browser | parked | a measured need on a fourth platform |
|
|
225
|
+
| Audio transcription fallback | parked | a video task failing specifically because no caption track exists |
|
|
226
|
+
|
|
227
|
+
**The credential-free scope was a deliberate cut, not an oversight.** Adding a
|
|
228
|
+
credential to any of these channels would put a secret on the same autonomous
|
|
229
|
+
path as untrusted third-party content (Reddit comment bodies, tweet HTML) and an
|
|
230
|
+
outbound fetch — all three legs of the lethal trifecta at once, which
|
|
231
|
+
`lethal-trifecta-guard` exists to prevent. Keeping every prescription
|
|
232
|
+
credential-free keeps that leg broken **by construction** rather than by
|
|
233
|
+
discipline. It also removed the whole consent-gate / credential-file /
|
|
234
|
+
account-ban surface that the design council named as the sharpest risk in this
|
|
235
|
+
area. The cut cost real capability (no timelines, no search, no metrics) and
|
|
236
|
+
that cost is recorded rather than hidden.
|
|
237
|
+
|
|
238
|
+
**One bound this amendment does not soften.** Reddit tier 2 is on an announced
|
|
239
|
+
closing path (login requirement announced 2026-06-30, still not enforced on the
|
|
240
|
+
bench machine on 2026-07-25). It ships with a kill-switch keyed on an
|
|
241
|
+
**observed** login wall — never on the announcement — plus a reverse trigger that
|
|
242
|
+
keeps the tier alive while logged-out access still works. A press release is not
|
|
243
|
+
an outage.
|
|
244
|
+
|
|
245
|
+
## References
|
|
246
|
+
|
|
247
|
+
- `internal/bench/reach-vs-native/README.md` — pre-registered tasks, thresholds, bands, run protocol.
|
|
248
|
+
- `internal/bench/reach-vs-native/VERDICT.md` — tally, per-channel S0a/S0b, `band: stop`, honest limitations.
|
|
249
|
+
- `docs/benchmark.md` § internet-reach — the published null.
|
|
250
|
+
- `internal/upstream-changes.md` — maintenance log for channel breakage.
|
|
251
|
+
- Council: anthropic/claude-sonnet-4-5 + openai/gpt-4o, 2026-07-24, 3 rounds — converged on the five structural defects of the first draft (impossible sequencing, rigged threshold, post-facto verdict, unfalsifiable acceptance criteria, unmechanized discipline claims); all five fixed before execution.
|
|
252
|
+
- `internal/bench/gated-reach/VERDICT.md` — per-channel verdicts + kill-switch criteria (Amendment 2026-07-25).
|
|
253
|
+
- `docs/guides/gated-platform-reads.md` — the shipped operator prescriptions.
|
|
254
|
+
- `src/skills/gated-reach/SKILL.md` — the ship-tier skill, triggers proven both directions.
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
---
|
|
2
|
+
adr: 127
|
|
3
|
+
status: accepted
|
|
4
|
+
date: 2026-07-25
|
|
5
|
+
decision: enforcement-claims-must-resolve
|
|
6
|
+
supersedes: —
|
|
7
|
+
superseded_by: —
|
|
8
|
+
phase: road-to-enforcement-proof · P1–P5
|
|
9
|
+
type: structural
|
|
10
|
+
review_trigger: >-
|
|
11
|
+
When resolved enforcement coverage stops rising across two consecutive
|
|
12
|
+
releases while rules keep being added — that would mean the field is being
|
|
13
|
+
filled in to satisfy the gate rather than to record a real backstop, and the
|
|
14
|
+
ratchet has become ceremony. Also reopen if a `validator:` declaration is
|
|
15
|
+
found resolving green through an indirection that does not actually execute
|
|
16
|
+
it, which would mean the reachability test has itself become fail-open.
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# ADR-127 — An enforcement claim must resolve, not merely exist
|
|
20
|
+
|
|
21
|
+
## Status
|
|
22
|
+
|
|
23
|
+
**Accepted** · 2026-07-25.
|
|
24
|
+
|
|
25
|
+
## Context
|
|
26
|
+
|
|
27
|
+
A source-level comparison against an external governance reference surfaced one
|
|
28
|
+
defect class this package could not see from the inside: **prose that asserts
|
|
29
|
+
enforcement the code does not deliver.** Four verification agents re-read every
|
|
30
|
+
load-bearing claim against this repo's own source. Five instances survived
|
|
31
|
+
verification:
|
|
32
|
+
|
|
33
|
+
- `src/rules/output-discipline.md` asserted "violations cause a CI exit-code-2"
|
|
34
|
+
while `lint_output_slop.ts` shipped and was wired into nothing.
|
|
35
|
+
- `check_kernel_rule_bundle.ts` — the one-kernel-rule-per-PR slow-rollout gate —
|
|
36
|
+
watched `.agent-src.uncondensed/rules`, a tree retired in the ADR-051 move to
|
|
37
|
+
`src/`. A path that cannot exist never matches, so the gate reported "no kernel
|
|
38
|
+
rule touched" for every kernel-rule edit, indefinitely.
|
|
39
|
+
- `docs/contracts/subagent-boundary.md` stated as fact that "every floor applies
|
|
40
|
+
inside the subagent"; the brief schema, the spawn composer, and all eight
|
|
41
|
+
worker-prompt templates contained no floor text at all.
|
|
42
|
+
- The override layer documented no non-overridable class, so the shipped consumer
|
|
43
|
+
README described unconditional whole-file shadowing — an empty file at
|
|
44
|
+
`agents/overrides/rules/non-destructive-by-default.md` reading as a way to
|
|
45
|
+
remove the Hard Floor.
|
|
46
|
+
- 128 ADRs, zero naming a revisit condition, because ADR frontmatter was
|
|
47
|
+
**entirely unvalidated** — `validate_frontmatter.ts` covered skills, rules,
|
|
48
|
+
commands, and personas and nothing covered `docs/decisions/`.
|
|
49
|
+
|
|
50
|
+
Nothing in the existing gate set could detect any of them, for one shared reason:
|
|
51
|
+
**every gate checked that a pointer resolves, never that a claim is true.** The
|
|
52
|
+
claims ledger is the clearest case — three evidence forms, all existence checks
|
|
53
|
+
(file present, substring present, URL carries a date), and a `last_verified`
|
|
54
|
+
field that is parsed and compared to nothing.
|
|
55
|
+
|
|
56
|
+
The reference object's most transferable norm, and the one adopted here: a rule
|
|
57
|
+
with no feasible enforcement tier is deleted rather than kept as honor-system
|
|
58
|
+
theatre, and a check with no real input is left unwired rather than run as
|
|
59
|
+
decoration. Notably, the reference violates its own version of this in two places
|
|
60
|
+
(a nucleus its ADR sizes at "~15 lines" that is 9; a freshness check its ADR
|
|
61
|
+
promises as FAIL that registers WARN) — which is itself evidence that the defect
|
|
62
|
+
class is structural, not a lapse of care.
|
|
63
|
+
|
|
64
|
+
## Decision
|
|
65
|
+
|
|
66
|
+
**An enforcement claim is credited only when it resolves against the filesystem
|
|
67
|
+
AND the wiring. Declaration is not evidence.**
|
|
68
|
+
|
|
69
|
+
1. Rules carry `enforced_by:` — `hook:` / `validator:` / `test:` / `observer:` /
|
|
70
|
+
`none` — and `check_enforcement_coverage.ts` **resolves** each value. A
|
|
71
|
+
`validator:` whose script exists but is reachable from no taskfile, workflow,
|
|
72
|
+
or hook manifest resolves to `unwired`, not covered. Reachability is
|
|
73
|
+
transitive, so a sub-check running under a wired umbrella counts; a mention in
|
|
74
|
+
a comment does not.
|
|
75
|
+
2. **Blocking and instrumenting are different tiers.** A hook registered
|
|
76
|
+
`fail_closed: false` resolves to `observer`, never `validator`. Of 18
|
|
77
|
+
registered hooks, exactly one can block.
|
|
78
|
+
3. `none` is legal and **counted**. Undeclared rules count as uncovered, not as
|
|
79
|
+
excluded — a coverage number over only the rules that opted in would be
|
|
80
|
+
flattering and useless. The published figure is 14 of 107 (13.1%).
|
|
81
|
+
4. **Kernel and safety-floor rules are non-overridable, with a registry.** A
|
|
82
|
+
`replace`-mode override on one is refused; an `extend` (a tightening) requires
|
|
83
|
+
an entry in `agents/overrides/kernel-exceptions.yml`. Direction matters, not
|
|
84
|
+
identity — this package's own legitimate override *tightens*
|
|
85
|
+
`verify-before-complete`, and a blanket name ban would forbid it.
|
|
86
|
+
5. **The override audit reports; it does not pretend to police.** A build-failing
|
|
87
|
+
lint on kernel-named override files would guard one of several routes by which
|
|
88
|
+
a consumer can tell a model to ignore a rule, and would relocate the rest out
|
|
89
|
+
of sight while reading as coverage. It hard-fails only on this package's own
|
|
90
|
+
authoring surface, where the coverage claim is true.
|
|
91
|
+
6. **The subagent floor is generated and delivered.** Derived from the kernel rule
|
|
92
|
+
list, written into every dispatch prompt in `src/` **and** the shipped
|
|
93
|
+
`dist/agent-src/` projection, drift-gated with a FAIL.
|
|
94
|
+
7. **ADRs name a revisit condition, not a cadence.** Required from 2026-07-25
|
|
95
|
+
forward, grandfathered by date rather than by an allowlist. A bare "annually"
|
|
96
|
+
is rejected — a calendar review is ignored; an event fires.
|
|
97
|
+
8. **`exec:` evidence is scheduled by measurement, not by appeal.** The threshold
|
|
98
|
+
(≥ 10 pp of the backed ledger) was pre-registered before the count was taken;
|
|
99
|
+
the measured figure is 10 of 25 feasible (40 pp) against 0 today, so it
|
|
100
|
+
proceeds — in its own PR, not this one.
|
|
101
|
+
|
|
102
|
+
## Consequences
|
|
103
|
+
|
|
104
|
+
**Good.** The defect class is now continuously measurable and ratcheted: blocking
|
|
105
|
+
coverage may not fall and unwired declarations may not rise. Two live defects
|
|
106
|
+
were closed on the first run (D1, and the kernel gate watching a dead path), and
|
|
107
|
+
a third — the floor missing from the shipped projection — was caught by grepping
|
|
108
|
+
`dist/` after the generator's first pass. The kernel rule list is single-sourced,
|
|
109
|
+
ending three copies and two "kept in sync with…" comments.
|
|
110
|
+
|
|
111
|
+
**Cost.** 86 rules are undeclared and drag the published number down; that is
|
|
112
|
+
intended, and it means the headline figure will look bad until the field is
|
|
113
|
+
filled in honestly. `enforced_by` is a schema change on an
|
|
114
|
+
`additionalProperties: false` schema, so it cannot be added ad hoc.
|
|
115
|
+
|
|
116
|
+
**Accepted limits, stated rather than papered over.** The override carve-out is a
|
|
117
|
+
norm with a partial gate: the layer is model-resolved, so an `extend` block whose
|
|
118
|
+
prose says "ignore the above" passes, and other relax routes (a persona file,
|
|
119
|
+
host config, a direct instruction) are outside its view. The subagent floor
|
|
120
|
+
covers dispatches through this package's templates; whether a host-native spawn
|
|
121
|
+
inherits anything is a host property this package does not control and does not
|
|
122
|
+
claim. `non-destructive-by-default` remains `enforced_by: none` — no script can
|
|
123
|
+
enforce "ask before you deploy", and adjacent hooks guard hook-bypass rather than
|
|
124
|
+
destructive intent, so claiming them would inflate the number.
|
|
125
|
+
|
|
126
|
+
## Alternatives
|
|
127
|
+
|
|
128
|
+
- **Declaration-only `enforced_by`.** Rejected: it would have rated
|
|
129
|
+
`output-discipline` as enforced, which is the exact defect that motivated this.
|
|
130
|
+
- **Blanket ban on kernel overrides.** Rejected on both council members'
|
|
131
|
+
reasoning: it forbids legitimate tightening, including this repo's own.
|
|
132
|
+
- **A build-failing kernel-override lint.** Rejected as security theatre — see
|
|
133
|
+
Decision 5.
|
|
134
|
+
- **Build `exec:` evidence first.** Rejected on sequencing: without the coverage
|
|
135
|
+
baseline there was no way to know whether a new evidence form, validator, and
|
|
136
|
+
renderer would move falsifiability by 7% or 60%.
|
|
137
|
+
- **Retrofit `review_trigger` across all 83 structural/security ADRs.** Rejected:
|
|
138
|
+
it would mean inventing ~80 conditions to satisfy a field. Three ADRs with
|
|
139
|
+
demonstrably time-bound premises were retrofitted (ADR-016, ADR-109, ADR-110).
|
|
140
|
+
|
|
141
|
+
## References
|
|
142
|
+
|
|
143
|
+
- `internal/reports/enforcement-coverage.json` — the ratcheted baseline.
|
|
144
|
+
- `internal/reports/exec-evidence-feasibility.json` — the pre-registered
|
|
145
|
+
measurement and its decision.
|
|
146
|
+
- `docs/proof.md` § 2b — the published coverage figure and the ledger's own limit.
|
|
147
|
+
- `docs/contracts/subagent-boundary.md` § Honest scope of the floor guarantee.
|
|
148
|
+
- `src/agent-src/contexts/override-system.md` § The non-overridable class.
|
|
149
|
+
- ADR-051 (`src/` as source of truth) — the move that silently disarmed the
|
|
150
|
+
kernel-bundle gate.
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
---
|
|
2
|
+
adr: 128
|
|
3
|
+
status: accepted
|
|
4
|
+
date: 2026-07-25
|
|
5
|
+
decision: executable-evidence-and-measured-escalation
|
|
6
|
+
supersedes: —
|
|
7
|
+
superseded_by: —
|
|
8
|
+
phase: road-to-executable-evidence · P1–P4
|
|
9
|
+
type: structural
|
|
10
|
+
review_trigger: >-
|
|
11
|
+
When an `exec:` claim is found green while the thing it asserts is false —
|
|
12
|
+
which would mean the exit code stopped carrying the verdict and the form has
|
|
13
|
+
become a more expensive pointer. Also reopen when a ledger surface is edited
|
|
14
|
+
by anyone other than the maintainer, because contributor access is the
|
|
15
|
+
premise the deferred tamper-chain disagreement turned on and this package
|
|
16
|
+
does not have it yet.
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# ADR-128 — Evidence that re-derives itself, and escalation that is measured before it bites
|
|
20
|
+
|
|
21
|
+
## Status
|
|
22
|
+
|
|
23
|
+
**Accepted** · 2026-07-25. Continues ADR-127.
|
|
24
|
+
|
|
25
|
+
## Context
|
|
26
|
+
|
|
27
|
+
ADR-127 made an enforcement claim resolve against the wiring rather than merely
|
|
28
|
+
exist, and closed five live defects doing it. It deliberately left one thing
|
|
29
|
+
measured and unbuilt, in its own Decision 8: the claims ledger still checked
|
|
30
|
+
that an evidence pointer **resolves**, never that the claim is **true**. A ledger
|
|
31
|
+
entry reading "the suite is green" whose pointer resolves to a report nobody
|
|
32
|
+
regenerated stays `backed` indefinitely — the pointer resolves, the claim is
|
|
33
|
+
false. The pre-registered threshold for building the fix was ≥ 10 pp of the
|
|
34
|
+
backed ledger, set before counting; the measurement came back 11 of 26 feasible.
|
|
35
|
+
|
|
36
|
+
A second round of the same external comparison raised four further candidates
|
|
37
|
+
and a council was run over the cut (two members, two rounds). Both members
|
|
38
|
+
independently scoped in the `exec:` form and a content-driven risk axis, and
|
|
39
|
+
scoped out filling the 86 undeclared `enforced_by` fields and a
|
|
40
|
+
lifecycle-scenario cost model. The reasoning is recorded below because kills
|
|
41
|
+
that are not written down get re-proposed by the next analysis round.
|
|
42
|
+
|
|
43
|
+
The missing risk axis is concrete rather than theoretical.
|
|
44
|
+
`discipline_profile: auto` resolves rigor by host capability — *how much
|
|
45
|
+
governance can this environment afford*. Nothing asks *how dangerous is this
|
|
46
|
+
diff*. The live combination that leaves open: a weak host plus a diff in the
|
|
47
|
+
installer's provenance path resolves to minimum discipline, which is precisely
|
|
48
|
+
the change class hardened in 9.6.0. The fix landed; the process escalation for
|
|
49
|
+
the next change of that class did not.
|
|
50
|
+
|
|
51
|
+
## Decision
|
|
52
|
+
|
|
53
|
+
**1. `exec:` is the fourth evidence form, and it re-runs the command.**
|
|
54
|
+
`exec:<command> -> <exit-code>`. The exit code carries the verdict. The
|
|
55
|
+
allowlist is a set of argv prefix tuples in
|
|
56
|
+
`src/scripts/_lib/exec_evidence.ts`, never a regex over a command string — a
|
|
57
|
+
regex over shell text is the classic bypass. Every argument after the matched
|
|
58
|
+
prefix is re-checked for shell metacharacters and repo escape, **including the
|
|
59
|
+
right-hand side of `--flag=value`**, without which `--rootdir=/etc` clears an
|
|
60
|
+
allowlist that only inspected the flag name.
|
|
61
|
+
|
|
62
|
+
**2. Re-execution is CI-only; the static half runs everywhere.** Whether a
|
|
63
|
+
pointer is well-formed and allowlisted is a property of the *ledger*, so it
|
|
64
|
+
fails on a laptop too. Whether the command actually passes is a property of the
|
|
65
|
+
*environment*, so it runs only on an ephemeral CI runner and never in a
|
|
66
|
+
consumer's checkout. Locally the gate reports `UNVERIFIED — re-execution is
|
|
67
|
+
CI-only, skipped locally`, never a silent pass.
|
|
68
|
+
|
|
69
|
+
**3. A skip is not a failure, and a failure is not a skip.** "Ran and
|
|
70
|
+
disagreed" is a finding. "Could not run" is not. Collapsing the two turns the
|
|
71
|
+
verifier into a rubber stamp in one direction or a nuisance in the other.
|
|
72
|
+
|
|
73
|
+
**4. The feasibility count was corrected down by one, by building it.** Of the
|
|
74
|
+
11 measured feasible, 10 survived contact. `context-token-reduction` was counted
|
|
75
|
+
feasible because `check_token_regression` re-derives token figures with a real
|
|
76
|
+
tokenizer — but the script reads `internal/bench/reports/projection-cost.json`,
|
|
77
|
+
which is gitignored as a per-run artefact, so the command is not self-sufficient
|
|
78
|
+
in a fresh checkout and exits 1. The `exec:` gate found this on its first CI
|
|
79
|
+
run. The corrected figure is 10 of 26 (38.5 pp), still far above the
|
|
80
|
+
pre-registered 10 pp bar, so the decision to build stands on the corrected
|
|
81
|
+
number too — the over-count changed the margin, not the verdict.
|
|
82
|
+
|
|
83
|
+
**5. The residue is published, not rounded away.** `docs/proof.md` states how
|
|
84
|
+
many backed claims re-derive themselves versus rest on a pointer, and lists each
|
|
85
|
+
non-re-executable claim with the reason: external cite, paid or stochastic
|
|
86
|
+
benchmark output, or a prose contract with no exit code to carry a verdict.
|
|
87
|
+
|
|
88
|
+
**6. Trust-boundary risk is classified now and gated later.** The classifier is
|
|
89
|
+
path-based and reproducible from the diff alone — no model judgement about
|
|
90
|
+
whether a change "feels risky". Three classes: authentication and token
|
|
91
|
+
handling; installer, provenance, publish, and subagent-spawn paths; governance
|
|
92
|
+
surfaces. The docs exemption is scoped to prose *about* a system, not to any
|
|
93
|
+
markdown file: in this repo the rules, `AGENTS.md`, and the kernel set are all
|
|
94
|
+
`.md` and are executable policy. An extension-only test classified
|
|
95
|
+
`src/rules/icon-consistency.md` as unclassified, which a test caught before the
|
|
96
|
+
report shipped.
|
|
97
|
+
|
|
98
|
+
**7. Escalation is additive and the direction is encoded, not left to callers.**
|
|
99
|
+
The host profile sets a floor; a risk trigger may only raise it. A weak host
|
|
100
|
+
must never be able to lower an escalation — that inversion is the entire failure
|
|
101
|
+
mode the second axis exists to prevent, so `escalated_floor` takes a maximum
|
|
102
|
+
rather than trusting each call site to get the order right.
|
|
103
|
+
|
|
104
|
+
**8. The non-declinable escalation is justified by measurement, and still not
|
|
105
|
+
built here.** The threshold — ≥ 5 of ~100 first-parent merges landing in a
|
|
106
|
+
trust-boundary class — was written into the roadmap before the report was first
|
|
107
|
+
read. Measured: **11 of 99**. That clears the bar, so a non-declinable class for
|
|
108
|
+
trust-boundary diffs is warranted and gets its own ADR and its own PR. It is
|
|
109
|
+
deliberately not enabled by this one, because it trades away something the
|
|
110
|
+
authority model holds (`agent-authority`, `ask-when-uncertain`) and that trade
|
|
111
|
+
deserves its own decision record rather than riding along inside a measurement.
|
|
112
|
+
|
|
113
|
+
**9. The prevented-failure table is generated and gated.** Each row names a
|
|
114
|
+
failure mode rather than a feature, and cites a ledger claim. A cited id that is
|
|
115
|
+
missing or not `backed` **throws** during generation. The format was borrowed
|
|
116
|
+
from the reference; the discipline was not available to borrow — the reference's
|
|
117
|
+
own equivalent table carries a headline efficiency figure that appears nowhere
|
|
118
|
+
else, an order of magnitude below the cheapest scenario in its own generated
|
|
119
|
+
benchmark. A number with nowhere to resolve is exactly what this ledger exists
|
|
120
|
+
to catch, so the table is held to the ledger's bar.
|
|
121
|
+
|
|
122
|
+
**10. Three candidates are closed rather than left open.**
|
|
123
|
+
|
|
124
|
+
- **Filling the 86 undeclared `enforced_by` fields — deferred.** You cannot fill
|
|
125
|
+
them honestly without first building 86 enforcement points; what you get
|
|
126
|
+
otherwise is 86 `TODO` values, which is *strictly worse than a blank*. The
|
|
127
|
+
blank is honest about non-coverage; the TODO is a promise. This is the exact
|
|
128
|
+
failure ADR-127's own `review_trigger` names.
|
|
129
|
+
- **Adversarial governance evals — killed.** A corpus of "user pressures the
|
|
130
|
+
agent to skip a gate" scores refusal as the pass condition, while this
|
|
131
|
+
package's documented authority model says the user decides. An eval asserting
|
|
132
|
+
"the agent must refuse when the user says no" would declare `agent-authority`
|
|
133
|
+
a security failure. The narrower question — does the enforcement mechanism
|
|
134
|
+
return non-zero — is already answerable per rule.
|
|
135
|
+
- **A governed-writes lint — killed as the wrong layer.** A static scan for
|
|
136
|
+
`fs.writeFile` against protected paths is simultaneously too weak
|
|
137
|
+
(`child_process.exec('… > file')` walks past it) and too strong (fixture setup
|
|
138
|
+
trips it). Same reasoning as ADR-127 Decision 5: a gate covering one route of
|
|
139
|
+
several, while reading as coverage, is theatre. The type system is the right
|
|
140
|
+
layer if this is ever worth closing.
|
|
141
|
+
|
|
142
|
+
**11. Tamper-evident chains — deferred with the disagreement recorded, not
|
|
143
|
+
resolved by fiat.** Round 1 argued a hash chain adds nothing Git does not
|
|
144
|
+
already provide, and that the external `git merge-base` line-prefix witness does
|
|
145
|
+
all the work. Round 2 found the hole in that: a line-prefix witness catches
|
|
146
|
+
**tail truncation** and does **not** catch **mid-sequence deletion** — dropping
|
|
147
|
+
entries 50–90 out of the middle leaves a diff that is not a prefix violation and
|
|
148
|
+
reads as an ordinary divergent branch. Neither round produced the number that
|
|
149
|
+
settles it, which is how often a ledger surface is edited by someone other than
|
|
150
|
+
the maintainer. That number is the revisit condition in this ADR's frontmatter.
|
|
151
|
+
|
|
152
|
+
## Consequences
|
|
153
|
+
|
|
154
|
+
**Good.** Machine-re-verifiable claims went from **0 to 10** of 27 backed. The
|
|
155
|
+
form found a real defect on its first CI run — the over-counted feasibility
|
|
156
|
+
entry — which is the gate doing the job it was built for, on itself. The risk
|
|
157
|
+
classifier caught its own docs-exemption bug through a test before its report
|
|
158
|
+
was published. Both are the intended shape: the instrument fails visibly rather
|
|
159
|
+
than reporting a comfortable number.
|
|
160
|
+
|
|
161
|
+
**Cost.** 17 of 27 backed claims still rest on pointers and cannot re-derive
|
|
162
|
+
themselves; that is now stated on the proof page rather than implied away. The
|
|
163
|
+
`exec:` allowlist is a maintenance surface — a renamed script silently drops a
|
|
164
|
+
claim from re-verification to static-only, and nothing yet detects that
|
|
165
|
+
downgrade.
|
|
166
|
+
|
|
167
|
+
**Accepted limits, stated rather than discovered later.** The allowlist only
|
|
168
|
+
covers commands whose exit code *is* the verdict; nothing about this form helps
|
|
169
|
+
a claim resting on a paid benchmark. The path classifier sees paths, not intent:
|
|
170
|
+
a dangerous change in a file it does not know about classifies as `none`, and
|
|
171
|
+
the class list is a judgement that will need revisiting as the tree moves. The
|
|
172
|
+
shadow report measures what *would* have escalated, which is not the same as
|
|
173
|
+
what *should* have — it cannot tell whether those 11 merges were actually
|
|
174
|
+
handled carelessly, only that they were in the class.
|
|
175
|
+
|
|
176
|
+
## Alternatives
|
|
177
|
+
|
|
178
|
+
- **Build `exec:` for all 26 claims.** Not possible, and the attempt would have
|
|
179
|
+
produced fake pointers for benchmark claims. 10 honest re-verifications beat
|
|
180
|
+
26 that only look uniform.
|
|
181
|
+
- **Ship the non-declinable escalation in this PR.** Rejected on sequencing: the
|
|
182
|
+
measurement justifies it, but an authority-model trade deserves a decision
|
|
183
|
+
record a reader can find, not a paragraph inside a measurement PR.
|
|
184
|
+
- **Let `exec:` run locally too.** Rejected: "commands execute in the repository
|
|
185
|
+
root with full filesystem access" is a property to confine, not to trust, and
|
|
186
|
+
a consumer's checkout has no business re-running this package's evidence.
|
|
187
|
+
- **A regex allowlist.** Rejected — the reason the tuple form exists.
|
|
188
|
+
- **Skip the prevented-failure table as marketing.** Rejected: the format names
|
|
189
|
+
failure modes rather than features, which is a better description of what this
|
|
190
|
+
package does than any feature list, and the ledger gate makes it falsifiable.
|
|
191
|
+
|
|
192
|
+
## References
|
|
193
|
+
|
|
194
|
+
- `internal/reports/exec-evidence-feasibility.json` — the pre-registered
|
|
195
|
+
measurement, its correction, and the built outcome.
|
|
196
|
+
- `internal/reports/risk-escalation-shadow.json` — 11 of 99 first-parent merges,
|
|
197
|
+
against a threshold fixed before the first read.
|
|
198
|
+
- `src/scripts/_lib/exec_evidence.ts`, `src/scripts/_lib/risk_paths.ts`.
|
|
199
|
+
- `tests/scripts/exec_evidence.test.ts` — the abuse cases for the allowlist and
|
|
200
|
+
the argument hardening.
|
|
201
|
+
- ADR-127 — the enforcement-resolution decision this continues.
|
package/docs/decisions/INDEX.md
CHANGED
|
@@ -127,6 +127,11 @@ _Auto-generated by `scripts/adr/regenerate_index.py`. Do not edit._
|
|
|
127
127
|
| [ADR-121](ADR-121-knowledge-sensitivity-classes.md) | Knowledge Sensitivity Classes | accepted | 2026-07-12 | — |
|
|
128
128
|
| [ADR-122](ADR-122-adversarial-verification-council.md) | Adversarial Verification Council | accepted | 2026-07-14 | — |
|
|
129
129
|
| [ADR-123](ADR-123-runtime-security-scope-and-spawn-hardening.md) | Runtime Security Scope And Spawn Hardening | accepted | 2026-07-20 | — |
|
|
130
|
+
| [ADR-124](ADR-124-embedded-engine-doctrine.md) | Embedded Engine Doctrine | accepted | 2026-07-23 | ADR-088 (engine-adoption interpretation only), ADR-094 (engine-adoption interpretation only) |
|
|
131
|
+
| [ADR-125](ADR-125-doc-screenshot-anonymization.md) | Doc Screenshot Anonymization | accepted | 2026-07-23 | — |
|
|
132
|
+
| [ADR-126](ADR-126-internet-reach-operator-tooling.md) | Internet Reach Operator Tooling | accepted | 2026-07-24 | — |
|
|
133
|
+
| [ADR-127](ADR-127-enforcement-claims-must-resolve.md) | Enforcement Claims Must Resolve | accepted | 2026-07-25 | — |
|
|
134
|
+
| [ADR-128](ADR-128-executable-evidence-and-measured-escalation.md) | Executable Evidence And Measured Escalation | accepted | 2026-07-25 | — |
|
|
130
135
|
| [ADR-200](ADR-200-python-to-typescript-migration.md) | Python To Typescript Migration | accepted | 2026-06-11 | — |
|
|
131
136
|
|
|
132
137
|
## Unnumbered (legacy)
|
|
@@ -134,3 +139,19 @@ _Auto-generated by `scripts/adr/regenerate_index.py`. Do not edit._
|
|
|
134
139
|
| # | Title | Status | Date | Supersedes |
|
|
135
140
|
|---|---|---|---|---|
|
|
136
141
|
| [ADR-rule-kernel-and-router](ADR-rule-kernel-and-router.md) | Rule Kernel And Router Roadmap Closure | accepted | 2026-05-06 | — |
|
|
142
|
+
|
|
143
|
+
## Decision records outside this directory
|
|
144
|
+
|
|
145
|
+
Scanned, not hand-listed. These files are titled `# ADR — …` and record a
|
|
146
|
+
decision, but live elsewhere in the tree. They are indexed here so a decision
|
|
147
|
+
cannot be unfindable merely because of where it was filed; their paths are
|
|
148
|
+
unchanged and their inbound references still resolve.
|
|
149
|
+
|
|
150
|
+
| File | Title | Status |
|
|
151
|
+
|---|---|---|
|
|
152
|
+
| `agents/settings/contexts/adr-always-budget-relief-strategy.md` | Always-Budget Relief Strategy (parked, reactivation-gated) | Decided |
|
|
153
|
+
| `agents/settings/contexts/adr-always-rule-context-split-not-viable.md` | Splitting an Always-rule into rule + `load_context:` is not viable under Model (b) | Decided |
|
|
154
|
+
| `agents/settings/contexts/adr-artifact-engagement.md` | Artefact-Engagement Telemetry | Decided |
|
|
155
|
+
| `agents/settings/contexts/adr-auto-rule-consolidation.md` | Auto-Rule Consolidation (review-routing + transient-references pairs) | locked |
|
|
156
|
+
| `agents/settings/contexts/adr-frugality-savings-baseline.md` | Frugality Canon Savings Baseline | Decided |
|
|
157
|
+
| `agents/settings/contexts/adr-work-engine-rename.md` | Universal Execution Engine: rename `implement_ticket` → `work_engine` | Decided |
|