@event4u/agent-config 14.7.0 → 14.9.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 +175 -390
- package/README.md +1 -1
- package/agents/templates/.ai-council.yml.example +34 -4
- package/dist/agent-src/commands/evals/git-pr-merge.json +13 -0
- package/dist/agent-src/commands/evals/roadmap.json +17 -1
- package/dist/agent-src/commands/pr/create.md +14 -2
- package/dist/agent-src/commands/pr/merge.md +383 -0
- package/dist/agent-src/commands/review/changes.md +95 -14
- package/dist/agent-src/commands/roadmap/process-full.md +157 -3
- package/dist/agent-src/commands/roadmap.md +1 -1
- package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +46 -36
- package/dist/agent-src/contexts/execution/autonomy-mechanics.md +37 -2
- package/dist/agent-src/contexts/execution/host-capability-manifest.md +77 -0
- package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +100 -2
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +154 -2
- package/dist/agent-src/contexts/execution/subagent-response-contract.md +80 -0
- package/dist/agent-src/rules/artifact-drafting-protocol.md +5 -1
- package/dist/agent-src/rules/decision-revisit-gate.md +65 -33
- package/dist/agent-src/rules/recurring-criticism.md +1 -1
- package/dist/agent-src/rules/roadmap-progress-sync.md +19 -0
- package/dist/agent-src/rules/source-confidentiality.md +1 -1
- package/dist/agent-src/rules/untrusted-input-defense.md +9 -3
- package/dist/agent-src/scripts/archive_completed_roadmaps.ts +7 -4
- package/dist/agent-src/scripts/dashboard_mode.ts +212 -0
- package/dist/agent-src/scripts/update_roadmap_progress.ts +47 -48
- package/dist/agent-src/skills/adr-create/SKILL.md +124 -5
- package/dist/agent-src/skills/code-review/evals/evals.json +87 -46
- package/dist/agent-src/skills/decision-record/SKILL.md +61 -3
- package/dist/agent-src/skills/decision-review/SKILL.md +65 -0
- package/dist/agent-src/skills/humanizer/SKILL.md +39 -0
- package/dist/agent-src/skills/humanizer/evals/strip_fixtures.json +57 -0
- package/dist/agent-src/skills/humanizer/references/fixtures.md +54 -0
- package/dist/agent-src/skills/judge-spec-compliance/SKILL.md +154 -0
- package/dist/agent-src/skills/judge-synthesis/SKILL.md +45 -0
- package/dist/agent-src/skills/merge-conflicts/SKILL.md +26 -0
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +18 -18
- package/dist/agent-src/skills/security/SKILL.md +8 -0
- package/dist/agent-src/skills/security-audit/SKILL.md +12 -1
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/roadmaps.md +28 -2
- package/dist/cli/registry.js +3 -0
- package/dist/cli/registry.js.map +1 -1
- package/dist/cli-delegate/{chunk-FBKL6JWT.js → chunk-77GR3VD4.js} +68 -43
- package/dist/cli-delegate/{chunk-JZ4NR2TW.js → chunk-7PRE6ZV2.js} +1 -1
- package/dist/cli-delegate/{chunk-UEZ7D35A.js → chunk-CYH5SP6M.js} +4 -23
- package/dist/cli-delegate/{chunk-Q26HT4QT.js → chunk-E46KPN6K.js} +251 -150
- package/dist/cli-delegate/{chunk-74E3TKWV.js → chunk-H4VIVD4C.js} +5 -5
- package/dist/cli-delegate/chunk-I3EIN2YG.js +36 -0
- package/dist/cli-delegate/{chunk-4VR4ORQ6.js → chunk-LPPWO5CE.js} +4 -3
- package/dist/cli-delegate/{chunk-7F3VYSM2.js → chunk-PLSG6UL5.js} +14 -14
- package/dist/cli-delegate/cmd_adr_effective.js +1162 -0
- package/dist/cli-delegate/cmd_conformance.js +101 -25
- package/dist/cli-delegate/cmd_converge.js +3 -3
- package/dist/cli-delegate/cmd_doctor.js +7 -7
- package/dist/cli-delegate/cmd_export.js +6 -6
- package/dist/cli-delegate/cmd_handoff.js +7 -6
- package/dist/cli-delegate/cmd_memory_get.js +2 -1
- package/dist/cli-delegate/cmd_migrate.js +2 -2
- package/dist/cli-delegate/cmd_preflight.js +5 -5
- package/dist/cli-delegate/cmd_prune.js +6 -6
- package/dist/cli-delegate/cmd_route_audit.js +6 -5
- package/dist/cli-delegate/cmd_route_explain.js +3 -3
- package/dist/cli-delegate/cmd_session_recycle.js +3 -3
- package/dist/cli-delegate/cmd_settings_get.js +4 -4
- package/dist/cli-delegate/cmd_settings_migrate.js +6 -6
- package/dist/cli-delegate/cmd_settings_set.js +1 -1
- package/dist/cli-delegate/cmd_sync.js +6 -6
- package/dist/cli-delegate/cmd_uninstall.js +6 -6
- package/dist/cli-delegate/cmd_update.js +3 -3
- package/dist/cli-delegate/cmd_upgrade.js +3 -3
- package/dist/cli-delegate/cmd_validate.js +6 -6
- package/dist/cli-delegate/cmd_versions.js +3 -3
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +83 -30
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +4 -4
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +11 -9
- package/dist/discovery/trust-report.md +2 -2
- package/dist/discovery/workspaces.json +9 -7
- package/dist/hooks/dispatch.js +1295 -812
- package/dist/install/globalRuleLayers.js +169 -0
- package/dist/install/globalRuleLayers.js.map +1 -0
- package/dist/install/partitionEligibility.js +156 -0
- package/dist/install/partitionEligibility.js.map +1 -1
- package/dist/install/ruleLayerPartition.js +157 -0
- package/dist/install/ruleLayerPartition.js.map +1 -0
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +1358 -805
- package/dist/scripts/_lib/claude_plugin.js +162 -0
- package/dist/scripts/_lib/claude_plugin.js.map +1 -0
- package/dist/scripts/_lib/environment_detector.js +397 -0
- package/dist/scripts/_lib/environment_detector.js.map +1 -0
- package/dist/scripts/_lib/prune_empty_dirs.js +85 -0
- package/dist/scripts/_lib/prune_empty_dirs.js.map +1 -0
- package/dist/scripts/_lib/spawn_env.js +129 -0
- package/dist/scripts/_lib/spawn_env.js.map +1 -0
- package/dist/scripts/ai_council/modes.js +199 -0
- package/dist/scripts/ai_council/modes.js.map +1 -0
- package/dist/scripts/ai_council/transport_resolver.js +418 -0
- package/dist/scripts/ai_council/transport_resolver.js.map +1 -0
- package/dist/scripts/condense.js +52 -89
- package/dist/scripts/condense.js.map +1 -1
- package/dist/server/routes/wizard.js +3 -2
- package/dist/server/routes/wizard.js.map +1 -1
- package/dist/ui/assets/index-Cxgy63kz.js +26 -0
- package/dist/ui/assets/index-Cxgy63kz.js.map +1 -0
- package/dist/ui/index.html +1 -1
- package/docs/guidelines/agent-infra/artifact-drafting-protocol-mechanics.md +45 -1
- package/docs/guidelines/agent-infra/false-green.md +47 -1
- package/docs/guidelines/agent-infra/traceability-field-mechanics.md +50 -0
- package/docs/guidelines/agent-infra/untrusted-input-spotlighting.md +17 -0
- package/package.json +7 -3
- package/src/agent-src/scripts/archive_completed_roadmaps.ts +7 -4
- package/src/agent-src/scripts/dashboard_mode.ts +212 -0
- package/src/agent-src/scripts/update_roadmap_progress.ts +47 -48
- package/src/config/ci-local-parity.yml +21 -0
- package/src/config/estate-count-budget.json +13 -471
- package/src/config/evaluator-budgets.json +4 -4
- package/src/config/gate-coverage.yml +458 -12
- package/src/config/gate-violation-baselines.json +18 -8
- package/src/config/gitignore-block.txt +15 -2
- package/src/config/hook-latency-budget.json +5 -0
- package/src/config/publish-surface.json +60 -0
- package/src/config/requirements-trace-budget.json +32 -0
- package/src/config/rule-stub-ceilings.json +25 -4
- package/src/install/globalRuleLayers.ts +197 -0
- package/src/install/partitionEligibility.ts +177 -0
- package/src/install/ruleLayerPartition.ts +212 -0
- package/src/scripts/_cli/cmd_adr_effective.ts +484 -0
- package/src/scripts/_dispatch.bash +18 -0
- package/src/scripts/_lib/adr_frontmatter.test.ts +365 -0
- package/src/scripts/_lib/adr_frontmatter.ts +459 -0
- package/src/scripts/_lib/base_tree.ts +175 -0
- package/src/scripts/_lib/billing_grant.ts +165 -0
- package/src/scripts/_lib/billing_grant_cli.ts +123 -0
- package/src/scripts/_lib/council_fallback_posture.ts +53 -6
- package/src/scripts/_lib/council_fallback_wiring.ts +61 -1
- package/src/scripts/_lib/envelope_grounding.ts +11 -1
- package/src/scripts/_lib/host_capability.ts +59 -5
- package/src/scripts/_lib/layer_overlap_notice.ts +11 -2
- package/src/scripts/_lib/prune_empty_dirs.ts +80 -0
- package/src/scripts/_lib/quota_parked.ts +133 -0
- package/src/scripts/_lib/retrieval_sanitize.ts +62 -0
- package/src/scripts/_lib/review_telemetry.ts +196 -0
- package/src/scripts/_lib/subagent_response.ts +92 -0
- package/src/scripts/adr/evidence_census.ts +899 -0
- package/src/scripts/adr/regenerate_index.ts +25 -38
- package/src/scripts/adr_cite_check.ts +540 -39
- package/src/scripts/ai_council/clients.ts +12 -1
- package/src/scripts/ai_council/config.ts +72 -115
- package/src/scripts/ai_council/fallback_config.ts +19 -7
- package/src/scripts/ai_council/mid_flight_fallback.ts +88 -7
- package/src/scripts/ai_council/orchestrator.ts +2 -2
- package/src/scripts/ai_council/py_format.ts +124 -0
- package/src/scripts/ai_council/transport_resolver.ts +65 -2
- package/src/scripts/audit_adr_coverage.ts +134 -21
- package/src/scripts/bench_hook_latency.ts +204 -0
- package/src/scripts/build_archive_index.ts +34 -0
- package/src/scripts/check_adr_frontmatter.ts +574 -39
- package/src/scripts/check_council_pin_staleness.ts +300 -0
- package/src/scripts/check_estate_count.ts +420 -293
- package/src/scripts/check_gate_coverage.ts +91 -0
- package/src/scripts/check_hook_bundle_content.ts +219 -0
- package/src/scripts/check_new_adr_evidence.ts +529 -0
- package/src/scripts/check_no_stub_inventory_table.ts +292 -0
- package/src/scripts/check_pack_size.ts +234 -1
- package/src/scripts/check_publish_surface.ts +297 -0
- package/src/scripts/check_references.ts +18 -0
- package/src/scripts/check_requirements_trace.ts +378 -0
- package/src/scripts/check_rule_layer_partition.ts +531 -0
- package/src/scripts/check_secret_leak.ts +166 -12
- package/src/scripts/check_single_delivery.ts +137 -4
- package/src/scripts/check_standing_rule_delivery.ts +8 -2
- package/src/scripts/code_graph/cli.ts +44 -5
- package/src/scripts/code_graph/extract.ts +87 -0
- package/src/scripts/condense.ts +61 -91
- package/src/scripts/council_cli.ts +12 -16
- package/src/scripts/detect_ai_tells.ts +87 -0
- package/src/scripts/dispatch_r2_reviewer.ts +42 -0
- package/src/scripts/external_sources_denylist.json +4 -1
- package/src/scripts/generate_capabilities_index.ts +41 -0
- package/src/scripts/git_authorization_hook.ts +54 -4
- package/src/scripts/hooks/block_unauthorized_git.ts +41 -3
- package/src/scripts/hooks/dispatch_hook.ts +154 -187
- package/src/scripts/hooks/dispatch_issues.ts +38 -19
- package/src/scripts/hooks/fallback_yaml.ts +66 -0
- package/src/scripts/hooks/host_semantics.ts +21 -0
- package/src/scripts/hooks/injection_budget.ts +13 -3
- package/src/scripts/hooks/py_json_dumps.ts +103 -0
- package/src/scripts/hooks/run_continuation_hook.ts +3 -1
- package/src/scripts/hooks/state_io.ts +88 -1
- package/src/scripts/hooks/stdin_failure_policy.ts +96 -0
- package/src/scripts/hooks/subagent_ledger_hook.ts +76 -11
- package/src/scripts/injection_scan_hook.ts +257 -15
- package/src/scripts/lint_adr_sweep_routing.ts +365 -0
- package/src/scripts/lint_hook_manifest.ts +49 -0
- package/src/scripts/lint_provenance_vocabulary.ts +472 -4
- package/src/scripts/lint_workflow_security.ts +53 -10
- package/src/scripts/lint_workflow_security_allowlist.json +2 -18
- package/src/scripts/report_envelope_rate.ts +166 -0
- package/src/scripts/review_axis_report.ts +218 -0
- package/src/scripts/routing_doctor.ts +5 -1
- package/src/scripts/run_supervise.ts +46 -1
- package/src/scripts/schemas/evals.schema.json +5 -0
- package/src/scripts/sync_pr_branch.ts +170 -20
- package/dist/cli/commands/commands.candidates.test.js +0 -257
- package/dist/cli/commands/commands.candidates.test.js.map +0 -1
- package/dist/cli/commands/profiles.test.js +0 -88
- package/dist/cli/commands/profiles.test.js.map +0 -1
- package/dist/cli/commands/recordTriggerEval.test.js +0 -113
- package/dist/cli/commands/recordTriggerEval.test.js.map +0 -1
- package/dist/cli/configRoot.test.js +0 -97
- package/dist/cli/configRoot.test.js.map +0 -1
- package/dist/cli/mcp/content.test.js +0 -54
- package/dist/cli/mcp/content.test.js.map +0 -1
- package/dist/cli/mcp/dispatch.test.js +0 -108
- package/dist/cli/mcp/dispatch.test.js.map +0 -1
- package/dist/server/writeRoot.test.js +0 -91
- package/dist/server/writeRoot.test.js.map +0 -1
- package/dist/shared/capabilities.test.js +0 -39
- package/dist/shared/capabilities.test.js.map +0 -1
- package/dist/ui/assets/index-C1pBRm1f.js +0 -26
- package/dist/ui/assets/index-C1pBRm1f.js.map +0 -1
- package/dist/cli-delegate/{chunk-PPQO4NGR.js → chunk-6RJA2F5A.js} +3 -3
- package/dist/cli-delegate/{chunk-6EOCNQAM.js → chunk-E4XIZDIB.js} +0 -0
- package/dist/cli-delegate/{chunk-GJ5BVHXM.js → chunk-PMEKGDED.js} +3 -3
|
@@ -42,16 +42,64 @@
|
|
|
42
42
|
#
|
|
43
43
|
# COVERAGE — THE HONEST DENOMINATOR (re-measured 2026-08-18)
|
|
44
44
|
# ----------------------------------------------------------
|
|
45
|
-
#
|
|
46
|
-
# (the count is computed, not asserted — `check_gate_coverage.count_gate_scripts
|
|
47
|
-
#
|
|
48
|
-
#
|
|
45
|
+
# 272 `lint_*` / `check_*` / `audit_*` scripts live under `src/scripts/`
|
|
46
|
+
# (the count is computed, not asserted — `check_gate_coverage.count_gate_scripts`,
|
|
47
|
+
# re-run 2026-08-22 and it returns 272).
|
|
48
|
+
# **47 of them emit the machine-readable `scanned: <N>` line under their
|
|
49
|
+
# CI-identical argv, and 44 of those 47 are listed below.** The manifest is
|
|
49
50
|
# therefore complete with respect to its own contract for every gate that can
|
|
50
|
-
# carry a floor, and covers ~
|
|
51
|
+
# carry a floor, and covers ~17 % of the population.
|
|
51
52
|
#
|
|
52
|
-
#
|
|
53
|
-
#
|
|
54
|
-
#
|
|
53
|
+
# RECOUNTED on 2026-08-22, and it was wrong on every figure before the recount —
|
|
54
|
+
# which is the fourth time, and the reason this paragraph keeps asking to be
|
|
55
|
+
# computed. `check_no_stub_inventory_table` added ONE row and ONE script, but the
|
|
56
|
+
# readings moved by more than one in three of the four places: population
|
|
57
|
+
# 269 -> 272 (two scripts had landed since 2026-08-21 without touching this
|
|
58
|
+
# prose), listed rows 42 -> 44 (the file already held 43 before this change; the
|
|
59
|
+
# prose had again been adjusted instead of recounted, and the paragraph below
|
|
60
|
+
# says so about its own previous revision), emitters 45 -> 47. Every number here
|
|
61
|
+
# is reproducible: `grep -c '^ - id:' src/config/gate-coverage.yml` for the rows
|
|
62
|
+
# and `count_gate_scripts()` for the population.
|
|
63
|
+
#
|
|
64
|
+
# Both halves were RE-DERIVED on 2026-08-21, not incremented, and the previous
|
|
65
|
+
# reading was off by one in a way worth recording: it said "42 … and 41 of those
|
|
66
|
+
# 42 are listed" while the file carried 42 rows AND named one deliberately
|
|
67
|
+
# unlisted emitter (`lint_evidence_artifacts`, below). Those three facts cannot
|
|
68
|
+
# all hold — 42 listed rows plus 1 unlisted emitter is 43 emitters, not 42. It
|
|
69
|
+
# is the same drift this section documents three times: an entry was added and
|
|
70
|
+
# the prose was adjusted by one instead of recounted.
|
|
71
|
+
#
|
|
72
|
+
# The derivation now, so the next reader can check it rather than trust it:
|
|
73
|
+
# `grep -c '^ - id:'` returns 44 (computable, and computed); every listed row
|
|
74
|
+
# is an emitter, because a row that did not emit could carry no floor and the
|
|
75
|
+
# guard would report it `failing`; THREE emitters are deliberately unlisted —
|
|
76
|
+
# `lint_evidence_artifacts` (below), `adr_cite_check` and
|
|
77
|
+
# `check_new_adr_evidence` (each in the block where its row would have sat);
|
|
78
|
+
# 44 + 3 = 47. The population figure comes from the function, and
|
|
79
|
+
# `check_new_adr_evidence` matches the population prefix whether or not it
|
|
80
|
+
# carries a row here.
|
|
81
|
+
#
|
|
82
|
+
# `adr/evidence_census` emits a `scanned:` line too and is NOT in either number:
|
|
83
|
+
# it carries no `lint|check|audit` prefix, so `count_gate_scripts()` never sees
|
|
84
|
+
# it. Named because the omission looks like a fourth miscount and is not one —
|
|
85
|
+
# an emitter outside the population cannot be an unlisted emitter within it.
|
|
86
|
+
#
|
|
87
|
+
# Corrected in completion review, and it is the third time this paragraph has
|
|
88
|
+
# been off by one — which is the argument for computing it rather than
|
|
89
|
+
# adjusting it. The previous reading said 43 listed and self-invited a `grep`
|
|
90
|
+
# that returns 42, so the check it offered refuted the sentence containing it.
|
|
91
|
+
# The cause each time is the same: a row was added or removed and the prose
|
|
92
|
+
# was incremented instead of recounted.
|
|
93
|
+
#
|
|
94
|
+
# A shape-grep over `src/scripts/` (`reportScanned(` or a literal `scanned: ${`)
|
|
95
|
+
# returns 63 files. That is a DIFFERENT population — any file carrying an emit
|
|
96
|
+
# shape, including gates that emit only in a non-CI mode — so it is not a
|
|
97
|
+
# recount of this sentence and must not be substituted for one.
|
|
98
|
+
#
|
|
99
|
+
# Three emitters are deliberately NOT listed, all for one reason. The first is
|
|
100
|
+
# `lint_evidence_artifacts`, for the same reason `check_rule_projection_integrity`
|
|
101
|
+
# is not (see the paragraph below): it is diff-scoped, so it legitimately emits
|
|
102
|
+
# `scanned: 0` on any
|
|
55
103
|
# branch that adds no evidence artifact, and `min_scanned: 0` is the
|
|
56
104
|
# false-count shape this file rejects. Its ledger half IS discharged — it
|
|
57
105
|
# adopts `_lib/gate_ledger.ts` and `_lib/scan_scope.ts`, so
|
|
@@ -169,11 +217,93 @@
|
|
|
169
217
|
# contract is `dist == rewrite(src)`; `check_ci_local_parity`, whose corpus is
|
|
170
218
|
# workflow files) carries no recipe and is reported UNPROVEN, never green.
|
|
171
219
|
gates:
|
|
220
|
+
- id: check_pack_size
|
|
221
|
+
argv: []
|
|
222
|
+
min_scanned: 2000
|
|
223
|
+
corpus: "the `npm pack --dry-run --ignore-scripts` payload — every file package.json `files[]` resolves (2,954 in a built worktree and 2,686 in an unbuilt one on 2026-08-22, which is why the floor sits well under both)"
|
|
224
|
+
status: enforced
|
|
225
|
+
canary:
|
|
226
|
+
class: contract-violation
|
|
227
|
+
path: src/scripts/zz-canary-shipped-credential.pem
|
|
228
|
+
content: |
|
|
229
|
+
zz canary probe: not a key, and deliberately not shaped like one.
|
|
230
|
+
The credential-shaped class matches on the PATH (`\.pem$`), never on the
|
|
231
|
+
body, so the plant needs no key-shaped content to red the class - and a
|
|
232
|
+
PEM header here would be a high-confidence check_secret_leak finding in
|
|
233
|
+
this tracked file. Measured, not guessed: the first draft carried a
|
|
234
|
+
BEGIN PRIVATE KEY block and reddened the secret gate at
|
|
235
|
+
gate-coverage.yml:229 in both `diff` and the new `pack` mode. A canary
|
|
236
|
+
that breaks a sibling gate to prove its own is not a canary.
|
|
237
|
+
note: >
|
|
238
|
+
ONE canary, and the entry shape is why. `canary:` is a single recipe per
|
|
239
|
+
gate id, not a list, while this gate carries FOUR content classes — so
|
|
240
|
+
per-class red observation lives in the gate's own `--self-test` (9 cases,
|
|
241
|
+
6 rejecting), which proves every class discriminates over a synthetic
|
|
242
|
+
payload with no pack run. Two of the four cannot be planted through the
|
|
243
|
+
register at all: `compiled-test-artefact` is excluded from the payload by
|
|
244
|
+
the `files[]` negations that fixed it, so a plant never ships and never
|
|
245
|
+
reds, and `source-map` needs 121 files in a BUILT tree.
|
|
246
|
+
|
|
247
|
+
The credential class is the one that gets the recipe. It is empty today,
|
|
248
|
+
and an empty class with no check is indistinguishable from a class nobody
|
|
249
|
+
looked at — so it is the class where "has this ever been red" is a real
|
|
250
|
+
question. The plant sits under `src/scripts/`, which IS a `files[]` root;
|
|
251
|
+
an earlier attempt under `src/skills/` was silently absent from the
|
|
252
|
+
payload because that path is not shipped, and a canary that cannot reach
|
|
253
|
+
the corpus proves nothing.
|
|
254
|
+
|
|
255
|
+
Floor is a count, not a size. The size arm has a budget file; the count
|
|
256
|
+
arm is what stops an empty payload — a botched `files[]`, a pack that
|
|
257
|
+
resolved nothing — from measuring 0 MB and passing every budget. The gate
|
|
258
|
+
already exits 2 rather than 0 on that, via `assertScanned`.
|
|
259
|
+
|
|
260
|
+
- id: check_secret_leak
|
|
261
|
+
argv: ["--pack"]
|
|
262
|
+
min_scanned: 2000
|
|
263
|
+
corpus: "the npm pack payload — every file package.json `files[]` resolves, INCLUDING shipped-but-gitignored paths no git-backed mode can reach (2,684 in an unbuilt worktree on 2026-08-22)"
|
|
264
|
+
status: enforced
|
|
265
|
+
canary:
|
|
266
|
+
class: contract-violation
|
|
267
|
+
path: dist/zz-canary-shipped-and-gitignored.pem
|
|
268
|
+
content: |
|
|
269
|
+
-----BEGIN RSA PRIVATE KEY-----
|
|
270
|
+
MIIEowIBAAKCAQEAzz-canary-not-a-real-key-zz
|
|
271
|
+
-----END RSA PRIVATE KEY-----
|
|
272
|
+
note: >
|
|
273
|
+
Registered on the `--pack` argv specifically, and the canary path is the
|
|
274
|
+
whole point: `dist/` is a `files[]` root while `/dist/*` is
|
|
275
|
+
`.gitignore:206`, so this plant is shipped and untracked at the same time.
|
|
276
|
+
`git check-ignore -q` matches it and `npm pack` includes it. A canary in a
|
|
277
|
+
tracked file would pass under the pre-existing `diff` and `all` modes too
|
|
278
|
+
and would prove nothing about the scope this entry exists for.
|
|
279
|
+
|
|
280
|
+
Measured, not assumed: with the plant in place `--pack` exits 1 and names
|
|
281
|
+
the path, while the default `diff` mode exits 0. The plant carries a real
|
|
282
|
+
PEM shape because THIS gate matches on CONTENT — unlike its sibling
|
|
283
|
+
`check_pack_size`, whose credential class matches on the path and whose
|
|
284
|
+
canary therefore deliberately carries no key-shaped body.
|
|
285
|
+
|
|
286
|
+
Two reasons the scope was blind, and adding the mode only fixed the first.
|
|
287
|
+
Mode enumeration walks the git tree; the `DEFAULT_EXCLUDE` list ALSO drops
|
|
288
|
+
all of `dist/`, regardless of mode. Until that exclusion became
|
|
289
|
+
mode-aware, the new scope resolved the payload and then filtered away
|
|
290
|
+
exactly the paths it was built to reach — the mode was measurably inert.
|
|
291
|
+
|
|
292
|
+
- id: check_publish_surface
|
|
293
|
+
argv: []
|
|
294
|
+
min_scanned: 2000
|
|
295
|
+
corpus: "the npm pack payload (2,686 in an unbuilt worktree on 2026-08-22), read to classify each .npmignore pattern against what actually shipped"
|
|
296
|
+
status: enforced
|
|
297
|
+
no_canary_reason: >-
|
|
298
|
+
the violation is a MODIFICATION, not a creation: this gate reds when package.json `files[]` or `.npmignore` changes and the committed artefact does not, and the canary contract is create-only. A planted FILE cannot move either surface — the closest it gets is changing the payload-derived shadowed set, which is informational and deliberately excluded from the drift verdict, so a plant would leave the gate green and be reported as dead. Discrimination is proven by the gate's own `--self-test` (8 cases, 5 rejecting) over the pattern matcher, and end to end by hand: editing `files[]` alone exits 1, regenerating exits 0, editing `.npmignore` alone exits 1, restoring exits 0.
|
|
299
|
+
|
|
172
300
|
- id: check_gate_completeness
|
|
173
301
|
argv: []
|
|
174
302
|
min_scanned: 180
|
|
175
303
|
corpus: "gates reachable from the `ci` / `consistency` task roots (220 at baseline)"
|
|
176
304
|
status: enforced
|
|
305
|
+
no_canary_reason: >-
|
|
306
|
+
whole-graph: it parses every gate invocation in the task roots at once, so a planted file has no property to violate — the defect it detects is a MISSING edge, which cannot be planted.
|
|
177
307
|
note: >
|
|
178
308
|
Floor set below the live count on purpose: the registered set legitimately
|
|
179
309
|
shrinks when a gate is retired, and a floor pinned at today's exact number
|
|
@@ -182,11 +312,37 @@ gates:
|
|
|
182
312
|
the Taskfile parse degrades and the population silently collapses —
|
|
183
313
|
cannot pass.
|
|
184
314
|
|
|
315
|
+
- id: check_rule_layer_partition
|
|
316
|
+
argv: []
|
|
317
|
+
min_scanned: 0
|
|
318
|
+
corpus: "the five project rule directories that receive a projected tree (.claude/rules, .cursor/rules, .clinerules, .windsurf/rules, .augment/rules)"
|
|
319
|
+
status: enforced
|
|
320
|
+
no_canary_reason: >-
|
|
321
|
+
cross-tree: the violation is one rule appearing in two projected trees, so it needs both trees, not a file.
|
|
322
|
+
note: >
|
|
323
|
+
`min_scanned: 0` is the honest floor and not the false-count shape this file
|
|
324
|
+
rejects elsewhere. This gate compares a project rule directory against its
|
|
325
|
+
host's GLOBAL layer, and on a fresh CI checkout neither side exists — the
|
|
326
|
+
project trees are gitignored and no CI leg installs at user scope. So the
|
|
327
|
+
population is legitimately zero there, exactly as it is for the diff-scoped
|
|
328
|
+
gates the header paragraph carves out.
|
|
329
|
+
What keeps a zero from reading as a pass is inside the gate rather than in
|
|
330
|
+
this floor: with nothing compared it prints "nothing compared — N skipped.
|
|
331
|
+
This is not a pass" instead of a success line, and every skip names the host
|
|
332
|
+
and the unreadable path. Teeth land on a working checkout, where `task
|
|
333
|
+
preflight` runs it against real global layers.
|
|
334
|
+
It never reports a duplicate for a host whose global layer cannot be read: a
|
|
335
|
+
project copy is the only carrier when the global one is absent, so demanding
|
|
336
|
+
its removal on unread evidence would delete the rule from that host —
|
|
337
|
+
the failure `partitionEligibility`'s fail-safe ordering exists to prevent.
|
|
338
|
+
|
|
185
339
|
- id: check_rule_activation_census
|
|
186
340
|
argv: []
|
|
187
341
|
min_scanned: 100
|
|
188
342
|
corpus: "rule files under src/rules/ (117 at baseline)"
|
|
189
343
|
status: enforced
|
|
344
|
+
no_canary_reason: >-
|
|
345
|
+
whole-corpus census: it reports an aggregate over every rule; a single planted rule moves a number rather than producing a red.
|
|
190
346
|
note: >
|
|
191
347
|
Floor set below the live count so a legitimate rule retirement does not red
|
|
192
348
|
the gate that watches activation. It is still far above a collapse: if the
|
|
@@ -280,22 +436,95 @@ gates:
|
|
|
280
436
|
min_scanned: 8
|
|
281
437
|
corpus: "declared human-authored suppression surfaces (10 at baseline)"
|
|
282
438
|
status: enforced
|
|
439
|
+
no_canary_reason: >-
|
|
440
|
+
cross-file: a suppression is a violation only against the declared surface that authorises it, so the pair is the unit.
|
|
283
441
|
note: >
|
|
284
442
|
The denominator is the INVENTORY, not the entry count — the gate's job is
|
|
285
443
|
that every suppression surface is accounted for, and a surface list that
|
|
286
444
|
collapsed to nothing must not read as "no suppressions to check".
|
|
287
445
|
|
|
446
|
+
- id: lint_adr_sweep_routing
|
|
447
|
+
argv: []
|
|
448
|
+
min_scanned: 20
|
|
449
|
+
corpus: "candidate rows (REVIEW-NOW / SUPERSEDE (candidate)) across docs/decisions/adr-evidence-sweep-*.md (26 at baseline, in one artifact)"
|
|
450
|
+
status: enforced
|
|
451
|
+
canary:
|
|
452
|
+
class: unrouted-candidate
|
|
453
|
+
path: docs/decisions/adr-evidence-sweep-zz-canary-probe.md
|
|
454
|
+
content: |
|
|
455
|
+
# ADR evidence sweep — canary probe
|
|
456
|
+
|
|
457
|
+
| Record | Disposition | Why |
|
|
458
|
+
|---|---|---|
|
|
459
|
+
| ADR-9999 | REVIEW-NOW | canary probe row |
|
|
460
|
+
|
|
461
|
+
## Candidate routing
|
|
462
|
+
|
|
463
|
+
| Record | Disposition | Route | Dated follow-up |
|
|
464
|
+
|---|---|---|---|
|
|
465
|
+
| ADR-9999 | REVIEW-NOW | council | when we get to it |
|
|
466
|
+
note: >
|
|
467
|
+
The floor is 20 rather than 26 because a candidate LEAVING the population
|
|
468
|
+
is the point of the sweep: every disposition that lands takes its row out
|
|
469
|
+
of the count, so a tight floor would red on the gate working. It is far
|
|
470
|
+
above a collapse — a scan that stopped seeing the artifact reports 0.
|
|
471
|
+
|
|
472
|
+
- id: check_requirements_trace
|
|
473
|
+
argv: []
|
|
474
|
+
min_scanned: 15
|
|
475
|
+
corpus: "roadmap files at the top level of agents/roadmaps/ (25 at registration, 2026-08-22)"
|
|
476
|
+
status: enforced
|
|
477
|
+
no_canary_reason: >-
|
|
478
|
+
this gate is a LISTING, not an enforcement: `main()` returns 0 on every
|
|
479
|
+
path and `process.exit(main())` is its only exit, so no planted file can
|
|
480
|
+
make it red and the harness's "caught the planted defect (exit 1)"
|
|
481
|
+
observation is unreachable by construction. Verified, not assumed — a probe
|
|
482
|
+
roadmap carrying an unresolved acceptance-criteria ref left the exit code at
|
|
483
|
+
0. It is registered for its `scanned:` floor, which is the one thing about
|
|
484
|
+
it that CAN break, and that floor is the negative control here.
|
|
485
|
+
note: >
|
|
486
|
+
A LISTING gate: it exits 0 always, including on a dangling `[AC:]` ref and
|
|
487
|
+
on an empty corpus. Registered here for its `scanned:` floor rather than
|
|
488
|
+
for a pass/fail verdict — the floor is the only thing about it that can
|
|
489
|
+
break, and a scan that stops seeing agents/roadmaps/ would otherwise
|
|
490
|
+
report an empty inventory as a clean one. Floor 15 against 25 at
|
|
491
|
+
registration: the active estate is being drained deliberately and is
|
|
492
|
+
expected to shrink, so a tight floor would red on the drain working.
|
|
493
|
+
|
|
494
|
+
- id: check_council_pin_staleness
|
|
495
|
+
argv: []
|
|
496
|
+
min_scanned: 3
|
|
497
|
+
corpus: "council members carrying a `model:` in agents/templates/.ai-council.yml.example (5 at registration, 2026-08-22)"
|
|
498
|
+
status: enforced
|
|
499
|
+
no_canary_reason: >-
|
|
500
|
+
the harness is create-only and this gate reads ONE fixed path
|
|
501
|
+
(agents/templates/.ai-council.yml.example), so no planted file lands inside
|
|
502
|
+
its scan scope — making it red means EDITING that template, which the
|
|
503
|
+
harness does not do. Discrimination is proven by the gate's own
|
|
504
|
+
`--self-test` instead: 10 cases across the fresh, stale, future-date,
|
|
505
|
+
malformed, unstamped and vendor-sentinel branches.
|
|
506
|
+
note: >
|
|
507
|
+
Floor 3 against 5 at registration: the template's member list is a shipped
|
|
508
|
+
artifact rather than a draining corpus, but an exact floor would red on a
|
|
509
|
+
legitimate trim of one member. Collapse is covered more strictly from the
|
|
510
|
+
other side — `reportScanned` raises DeadScopeError at 0 members, before
|
|
511
|
+
this floor is consulted at all.
|
|
512
|
+
|
|
288
513
|
- id: lint_trigger_collisions
|
|
289
514
|
argv: []
|
|
290
515
|
min_scanned: 90
|
|
291
516
|
corpus: "src/rules/*.md frontmatters (111 at baseline)"
|
|
292
517
|
status: enforced
|
|
518
|
+
no_canary_reason: >-
|
|
519
|
+
pairwise: a collision needs two rules, and which two is the finding — a single planted file collides with nothing.
|
|
293
520
|
|
|
294
521
|
- id: lint_rule_skill_pack_reach
|
|
295
522
|
argv: ["--quiet"]
|
|
296
523
|
min_scanned: 90
|
|
297
524
|
corpus: "src/rules/*.md frontmatters joined against src/skills packs and the pack registry (116 rules at baseline)"
|
|
298
525
|
status: enforced
|
|
526
|
+
no_canary_reason: >-
|
|
527
|
+
join: rule frontmatter against the skills tree and the pack registry; a planted rule needs a matching planted pack graph to be judged.
|
|
299
528
|
note: >
|
|
300
529
|
Advisory on findings, enforced on COVERAGE: the gate exits 0 while its
|
|
301
530
|
unreachable-route set is non-empty (12 at introduction), so only this
|
|
@@ -308,6 +537,8 @@ gates:
|
|
|
308
537
|
min_scanned: 380
|
|
309
538
|
corpus: "src/ ↔ dist/agent-src/ .md pairs (429 at baseline: 111 rules + 318 skills)"
|
|
310
539
|
status: enforced
|
|
540
|
+
no_canary_reason: >-
|
|
541
|
+
byte-equality between src/ and dist/agent-src/ pairs — the property is a relation between two trees, not a file.
|
|
311
542
|
|
|
312
543
|
- id: check_augment_description_cap
|
|
313
544
|
argv: []
|
|
@@ -418,6 +649,8 @@ gates:
|
|
|
418
649
|
min_scanned: 340
|
|
419
650
|
corpus: "CI + local gate invocations parsed from .github/workflows + taskfiles (360 measured 2026-08-13: 109 CI + 251 local)"
|
|
420
651
|
status: enforced
|
|
652
|
+
no_canary_reason: >-
|
|
653
|
+
whole-graph: it parses every workflow and taskfile invocation and reports gates present in one set and absent from the other.
|
|
421
654
|
note: >
|
|
422
655
|
Registered 2026-08-02. It already emitted the contract line on every path,
|
|
423
656
|
including the failing one — it was simply never listed, the same omission
|
|
@@ -465,6 +698,8 @@ gates:
|
|
|
465
698
|
unavailable_exit: 2
|
|
466
699
|
corpus: "built HTML pages under site/dist (25 content sources at baseline)"
|
|
467
700
|
status: enforced
|
|
701
|
+
no_canary_reason: >-
|
|
702
|
+
needs the BUILT site under site/dist, which does not exist until a build runs; already reported `unavailable` when absent.
|
|
468
703
|
note: >
|
|
469
704
|
Registered 2026-07-30 after it was caught reporting green over a stale build —
|
|
470
705
|
6 pages against 25 content sources, every source newer than the newest page.
|
|
@@ -494,6 +729,8 @@ gates:
|
|
|
494
729
|
min_scanned: 1200
|
|
495
730
|
corpus: "all .md under src/ + dist/agent-src/ plus the shipped root files (1,566 at baseline)"
|
|
496
731
|
status: enforced
|
|
732
|
+
no_canary_reason: >-
|
|
733
|
+
a planted file would be judged, but the gate is a broad scan whose baseline is the corpus size — a single red proves the matcher fires, which its own fixtures already do.
|
|
497
734
|
note: >
|
|
498
735
|
SCAN_DIRS named the retired authoring root, so the entire src/ tree —
|
|
499
736
|
more than half the corpus — was skipped and an identifier authored there
|
|
@@ -504,6 +741,8 @@ gates:
|
|
|
504
741
|
min_scanned: 800
|
|
505
742
|
corpus: ".md under the scanned roots plus memory YAML (1,043 at baseline)"
|
|
506
743
|
status: enforced
|
|
744
|
+
no_canary_reason: >-
|
|
745
|
+
a planted broken reference is judged, but every target must exist in the real tree for the resolver to be faithful; an isolated fixture makes every reference broken.
|
|
507
746
|
note: >
|
|
508
747
|
src/ was absent from every reference-resolution candidate list, so a link
|
|
509
748
|
resolvable only under the source of truth was reported BROKEN. The
|
|
@@ -515,6 +754,8 @@ gates:
|
|
|
515
754
|
min_scanned: 400
|
|
516
755
|
corpus: "src/rules + src/skills + src/agent-src/commands + docs/guidelines .md (533 at baseline)"
|
|
517
756
|
status: enforced
|
|
757
|
+
no_canary_reason: >-
|
|
758
|
+
thresholds are computed across the whole corpus; a single planted artefact has no population to exceed.
|
|
518
759
|
note: >
|
|
519
760
|
A collapse below the floor would mean the gate stopped reading the tree
|
|
520
761
|
that states extraction thresholds, so a bare or diverging threshold
|
|
@@ -525,6 +766,8 @@ gates:
|
|
|
525
766
|
min_scanned: 5
|
|
526
767
|
corpus: "src/agent-src/profiles/*.yml (6 seed profiles at baseline)"
|
|
527
768
|
status: enforced
|
|
769
|
+
no_canary_reason: >-
|
|
770
|
+
join: a profile is judged against the persona set it names, so both sides are needed.
|
|
528
771
|
note: >
|
|
529
772
|
Fewer than 5 profiles scanned would mean the gate stopped reading the
|
|
530
773
|
seed-profile dir, so a defaults.personas id that resolves to no persona
|
|
@@ -535,6 +778,8 @@ gates:
|
|
|
535
778
|
min_scanned: 200
|
|
536
779
|
corpus: "src/skills/*/SKILL.md (288 at baseline)"
|
|
537
780
|
status: enforced
|
|
781
|
+
no_canary_reason: >-
|
|
782
|
+
ratio gate: the 15% rich-skill cap is a property of the corpus, so one planted skill cannot cross it.
|
|
538
783
|
note: >
|
|
539
784
|
A collapse below the floor would mean the gate stopped reading the skills
|
|
540
785
|
tree, so a rich-tagged skill without its justification section (or a cap
|
|
@@ -545,6 +790,8 @@ gates:
|
|
|
545
790
|
min_scanned: 350
|
|
546
791
|
corpus: "skills / rules / commands .md actually judged (368 of 438 enumerated; the rest carry a declared exemption the ledger names)"
|
|
547
792
|
status: enforced
|
|
793
|
+
no_canary_reason: >-
|
|
794
|
+
the allowlist is line-keyed against real files, so a planted file has no allowlist anchor and the exemption path goes untested.
|
|
548
795
|
note: >
|
|
549
796
|
Its human summary prints "N hits across M files", where M is files WITH
|
|
550
797
|
HITS — 0 on a clean run. Reading that as coverage is precisely how a
|
|
@@ -555,14 +802,64 @@ gates:
|
|
|
555
802
|
|
|
556
803
|
- id: lint_plan_risk_register
|
|
557
804
|
argv: []
|
|
558
|
-
min_scanned:
|
|
559
|
-
corpus: "ready roadmap files under agents/roadmaps/ top level (19 at baseline: 14 grandfathered + 4 draft-exempt + 1 carrying a live register)"
|
|
805
|
+
min_scanned: 1
|
|
806
|
+
corpus: "ready roadmap files under agents/roadmaps/ top level (6 as of 2026-08-21; 19 at the original baseline: 14 grandfathered + 4 draft-exempt + 1 carrying a live register)"
|
|
560
807
|
status: enforced
|
|
808
|
+
no_canary_reason: >-
|
|
809
|
+
a planted roadmap is judged, but the gate reads the ready-roadmap population to decide scope; an isolated file changes what it scans.
|
|
561
810
|
note: >
|
|
562
811
|
Gate R1 (docs/contracts/plan-review-gates.md § 1). The count is READY
|
|
563
812
|
FILES INSPECTED incl. grandfathered/draft-exempt ones — exemptions are
|
|
564
|
-
reported, never silently skipped
|
|
565
|
-
|
|
813
|
+
reported, never silently skipped.
|
|
814
|
+
|
|
815
|
+
Lowered 12 → 5 on 2026-08-21, and the SHAPE of the change matters more
|
|
816
|
+
than the number. The previous note asserted that "a collapse below the
|
|
817
|
+
floor means the roadmaps root moved, not that the corpus went clean."
|
|
818
|
+
That premise is falsified: archiving roadmaps at zero open and zero
|
|
819
|
+
deferred steps dropped the top-level count from 12 to 10 with the root
|
|
820
|
+
untouched — the corpus really did go cleaner, which is what
|
|
821
|
+
road-to-estate-drawdown exists to achieve. A floor pinned to the exact
|
|
822
|
+
corpus size fails on the drawdown succeeding, which is the wrong thing
|
|
823
|
+
to detect.
|
|
824
|
+
|
|
825
|
+
So the replacement is deliberately NOT today's count. Re-pinning at 10
|
|
826
|
+
would repeat the defect one archival later and force this note to be
|
|
827
|
+
rewritten every time a roadmap closes. 5 sits structurally below any
|
|
828
|
+
plausible active set while still catching the two failures this floor is
|
|
829
|
+
for: the roadmaps root moving, and the scanner silently reading nothing.
|
|
830
|
+
It is not a target for how many roadmaps ought to exist.
|
|
831
|
+
|
|
832
|
+
Count reconciliation, since two numbers move in this change and they
|
|
833
|
+
count different populations: this gate counts READY files at the top
|
|
834
|
+
level of agents/roadmaps/ (12 → 10 here), while
|
|
835
|
+
estate-count-budget.json::active_roadmaps counts NON-DRAFT candidates as
|
|
836
|
+
collect() sees them (11 → 10). The gap is the draft-status file each
|
|
837
|
+
population treats differently; neither number is derivable from the
|
|
838
|
+
other.
|
|
839
|
+
|
|
840
|
+
Revisit-if the active set is deliberately grown past ~15, at which point
|
|
841
|
+
5 is uninformatively low, or if a drop is ever traced to a scanner
|
|
842
|
+
defect rather than to archival — either falsifies the number, not the
|
|
843
|
+
obligation.
|
|
844
|
+
|
|
845
|
+
Lowered again 10 → 5 on 2026-08-21, during the PR drain that produced the
|
|
846
|
+
paragraph above. 10 was measured against 12 and the drain had already
|
|
847
|
+
taken the corpus to 11 — one file of headroom, so the next archival would
|
|
848
|
+
have reddened CI for the exact reason this entry says is the wrong thing to
|
|
849
|
+
detect. 5 keeps the root-moved / scanner-blind signal (both scan 0) and
|
|
850
|
+
stops the number from needing a commit per archived roadmap.
|
|
851
|
+
|
|
852
|
+
Lowered again 5 → 1, and this time the SHAPE changed rather than the
|
|
853
|
+
number. 5 was picked to have headroom and did not: the drain took the
|
|
854
|
+
corpus to 6, so a review provoked the red by archiving one roadmap. The
|
|
855
|
+
lesson is that no absolute floor survives here — this gate's sibling
|
|
856
|
+
`check_estate_count` forbids growth, so the corpus can only shrink and any
|
|
857
|
+
floor above 0 is met eventually. 1 is the smallest value that still
|
|
858
|
+
distinguishes "the scanner read something" from "the root moved or the
|
|
859
|
+
scope is dead", which is the only thing this field was ever asked to
|
|
860
|
+
detect. Revisit-if the gate gains a way to express "non-empty" directly,
|
|
861
|
+
or if a drop to 0 is ever traced to a scanner defect rather than to an
|
|
862
|
+
empty corpus.
|
|
566
863
|
|
|
567
864
|
- id: check_estate_count
|
|
568
865
|
argv: []
|
|
@@ -597,6 +894,8 @@ gates:
|
|
|
597
894
|
min_scanned: 1
|
|
598
895
|
corpus: "findings artefacts under agents/evidence/reviews/ + the current-diff evaluation (1 at baseline — the evaluation itself; artefact count grows with gated PRs)"
|
|
599
896
|
status: enforced
|
|
897
|
+
no_canary_reason: >-
|
|
898
|
+
git-dependent: it evaluates the current diff against a base ref.
|
|
600
899
|
note: >
|
|
601
900
|
Gate R2 (docs/contracts/plan-review-gates.md § 2). HONEST LIMIT, stated
|
|
602
901
|
because a floor that cannot fail is exactly the false green this file
|
|
@@ -624,6 +923,8 @@ gates:
|
|
|
624
923
|
min_scanned: 7
|
|
625
924
|
corpus: "archived round records — `*-review.md` under agents/evidence/reviews/, excluding live `*.findings.md` (9 at baseline)"
|
|
626
925
|
status: enforced
|
|
926
|
+
no_canary_reason: >-
|
|
927
|
+
git-dependent in effect: it reads archived round records whose identity comes from the committed tree, and its own scan-scope guard fails on an empty corpus.
|
|
627
928
|
note: >
|
|
628
929
|
Contract § 2.7. Unlike the R2 entry above, this floor is genuinely
|
|
629
930
|
trippable: the corpus is 9 frozen records and archived records are not
|
|
@@ -653,6 +954,8 @@ gates:
|
|
|
653
954
|
min_scanned: 250
|
|
654
955
|
corpus: "src/skills/*/SKILL.md (288 at baseline)"
|
|
655
956
|
status: enforced
|
|
957
|
+
no_canary_reason: >-
|
|
958
|
+
join: a handoff is a link from one skill to another, so the target skill must exist to judge the link.
|
|
656
959
|
note: >
|
|
657
960
|
The argv here is load-bearing, not decoration. Taskfile injects `--quiet`
|
|
658
961
|
(QUIET_FLAG) and this gate read `args[0]` as a positional path, so the CI
|
|
@@ -667,6 +970,8 @@ gates:
|
|
|
667
970
|
min_scanned: 540
|
|
668
971
|
corpus: "names across src/rules + src/skills + src/agent-src + src/domains/**/command.md (621 at baseline)"
|
|
669
972
|
status: enforced
|
|
973
|
+
no_canary_reason: >-
|
|
974
|
+
collision gate across four roots at once; one planted name collides with nothing.
|
|
670
975
|
note: >
|
|
671
976
|
Counts NAMES, not files — the scan-scope census counts files under the same
|
|
672
977
|
roots, so the two artefacts legitimately report different numbers here.
|
|
@@ -676,12 +981,16 @@ gates:
|
|
|
676
981
|
min_scanned: 540
|
|
677
982
|
corpus: "artefacts carrying frontmatter across the discovery roots (619 at baseline)"
|
|
678
983
|
status: enforced
|
|
984
|
+
no_canary_reason: >-
|
|
985
|
+
a planted artefact is judged, but the gate reports adoption across the discovery roots, so the number rather than a red is the output.
|
|
679
986
|
|
|
680
987
|
- id: audit_skill_overlap
|
|
681
988
|
argv: ["--quiet", "--print-table", "--strict"]
|
|
682
989
|
min_scanned: 250
|
|
683
990
|
corpus: "src/skills/*/SKILL.md compared pairwise (288 at baseline)"
|
|
684
991
|
status: enforced
|
|
992
|
+
no_canary_reason: >-
|
|
993
|
+
pairwise over 288 skills; overlap needs a corpus, and which pair is the finding.
|
|
685
994
|
note: >
|
|
686
995
|
`--strict` is part of the CI invocation and can exit non-zero on a real
|
|
687
996
|
overlap finding. The guard reads the count independently of the exit code —
|
|
@@ -692,15 +1001,31 @@ gates:
|
|
|
692
1001
|
min_scanned: 90
|
|
693
1002
|
corpus: "src/rules/*.md (111 at baseline)"
|
|
694
1003
|
status: enforced
|
|
1004
|
+
no_canary_reason: >-
|
|
1005
|
+
a planted rule IS judgeable — this entry is a genuine authoring gap rather than a structural one, and is the first candidate if the mode is ever built.
|
|
695
1006
|
note: >
|
|
696
1007
|
Emits on stderr, not stdout: `--format json` owns this gate's stdout and a
|
|
697
1008
|
count written there would corrupt the payload. The guard reads both streams.
|
|
1009
|
+
Corpus boundary, decided 2026-08-20 (council, `leave-unscanned`): `src/skills`
|
|
1010
|
+
is deliberately OUT of this gate's corpus. Pointed at it the gate reports 13
|
|
1011
|
+
findings (11 `buried_iron_law`, 2 `deep_iron_law`) that nobody currently sees.
|
|
1012
|
+
Extending the corpus was declined on three grounds — the gate has no warn
|
|
1013
|
+
level, so a staged extension would mean adding a warning mode to an enforced
|
|
1014
|
+
blocking gate; the reverted `lint_skill_top_position` attempt showed two gates
|
|
1015
|
+
defining one construct incompatibly, and the disputed `deep_iron_law` class is
|
|
1016
|
+
still live in those 13; and the premise for scanning skills at all
|
|
1017
|
+
(post-compaction truncation keeps the file start) is unverified, the tree's one
|
|
1018
|
+
measured truncation fact being ENTRY-level. Re-opening this needs a measured
|
|
1019
|
+
reason plus the reported-and-baselined ratchet, not a path added to `argv`.
|
|
1020
|
+
See `agents/roadmaps/archive/road-to-context-fidelity.md` § Phase 3.
|
|
698
1021
|
|
|
699
1022
|
- id: check_cli_registry_budget_sync
|
|
700
1023
|
argv: []
|
|
701
1024
|
min_scanned: 3
|
|
702
1025
|
corpus: "the three named inputs it cross-checks — src/cli/registry.ts, src/config/evaluator-budgets.json, internal/bench/reports/evaluator-measurements.json"
|
|
703
1026
|
status: enforced
|
|
1027
|
+
no_canary_reason: >-
|
|
1028
|
+
git-dependent cross-check of three named committed inputs; the property is their agreement, not any one file.
|
|
704
1029
|
note: >
|
|
705
1030
|
Registered because its count became REAL, not to pad the manifest. The
|
|
706
1031
|
gate always printed a hardcoded `scanned: 3`; hardening derived it from
|
|
@@ -714,6 +1039,8 @@ gates:
|
|
|
714
1039
|
min_scanned: 100
|
|
715
1040
|
corpus: "leaf keys in src/config/agent-settings.template.yml (140 at baseline)"
|
|
716
1041
|
status: enforced
|
|
1042
|
+
no_canary_reason: >-
|
|
1043
|
+
the only possible violation is a MODIFICATION of two tracked files (a key added to the template, or a row removed from the contract) and the canary harness is create-only by design. Discrimination is proven by the gate's own `--self-test` instead — six rejecting cases including the dead-scan-root one.
|
|
717
1044
|
note: >
|
|
718
1045
|
Floor set well below the live 140 so retiring a settings key does not red
|
|
719
1046
|
the change that retires it, but high enough that the collapse this file
|
|
@@ -913,6 +1240,8 @@ gates:
|
|
|
913
1240
|
min_scanned: 1
|
|
914
1241
|
corpus: "rows of the `docs/MIGRATION.md` scheduled-deprecations table (3 at baseline)"
|
|
915
1242
|
status: enforced
|
|
1243
|
+
no_canary_reason: >-
|
|
1244
|
+
discrimination is proven by the gate's own `--self-test` (10 cases, 6 rejecting) driving the real binary, which covers the due-at-the-cut case a create-only canary could not express.
|
|
916
1245
|
note: >
|
|
917
1246
|
`argv` carries `--quiet` because that is what the task passes: the
|
|
918
1247
|
Taskfile resolves `{{.QUIET_FLAG}}` to `--quiet` unless
|
|
@@ -942,6 +1271,8 @@ gates:
|
|
|
942
1271
|
min_scanned: 900
|
|
943
1272
|
corpus: "TypeScript sources — src/**/*.ts excluding *.d.ts and *.test.ts, the same two kinds _lib/gate_population excludes (1,063 at baseline)"
|
|
944
1273
|
status: enforced
|
|
1274
|
+
no_canary_reason: >-
|
|
1275
|
+
the canary contract is create-only and this gate's violation is a MODIFICATION — a file crossing its line ceiling. Discrimination is proven by the gate's own `--self-test`, including a boundary case and a dead scan root.
|
|
945
1276
|
# No `canary:` recipe, and the reason is the canary contract's own shape
|
|
946
1277
|
# rather than a gap. The violation this gate detects is a file OVER 1,500
|
|
947
1278
|
# lines, so a create-only recipe would have to inline 1,501 lines of content
|
|
@@ -955,3 +1286,118 @@ gates:
|
|
|
955
1286
|
# an already-listed file that GREW while the file COUNT stayed at one. That
|
|
956
1287
|
# last case is what pins the metric as excess lines rather than a file count;
|
|
957
1288
|
# a count-based ratchet passes it, and this gate must not.
|
|
1289
|
+
|
|
1290
|
+
- id: check_no_stub_inventory_table
|
|
1291
|
+
argv: ["--quiet"]
|
|
1292
|
+
min_scanned: 1
|
|
1293
|
+
corpus: "the guarded watch list — agents/roadmaps/stubs/README.md (1 file; the whole scope, not a sample)"
|
|
1294
|
+
status: enforced
|
|
1295
|
+
no_canary_reason: >-
|
|
1296
|
+
the guarded path already EXISTS, so a create-only canary cannot plant the violation. Discrimination is proven by the gate's own `--self-test`.
|
|
1297
|
+
# No `canary:` recipe: the guarded path already EXISTS, and the canary
|
|
1298
|
+
# contract is create-only. A recipe would have to mutate a tracked file
|
|
1299
|
+
# rather than plant one, which the contract does not express. The gate
|
|
1300
|
+
# reports UNPROVEN there rather than green, which is the honest state.
|
|
1301
|
+
#
|
|
1302
|
+
# Discrimination is proven by the gate's own `--self-test` instead, and the
|
|
1303
|
+
# five cases are the sabotage probes it was verified with before landing:
|
|
1304
|
+
# a restored transfer table, the inventory header alone, a DEAD watch list
|
|
1305
|
+
# (the `check_safety_floor_untouched` shape — it must red, never report
|
|
1306
|
+
# clean), plus two accepting cases that pin the narrowness review asked for
|
|
1307
|
+
# — a glossary table and a table citing parent roadmaps one directory up
|
|
1308
|
+
# must both pass. A blanket ban on markdown tables in the file would trade
|
|
1309
|
+
# one regression for a permanent block on legitimate documentation.
|
|
1310
|
+
#
|
|
1311
|
+
# `min_scanned: 1` is the true corpus, not a weak floor: the scope is one
|
|
1312
|
+
# known file. The collapse this file's rule 3 guards against is covered by
|
|
1313
|
+
# `assertWatchlistResolves`, which refuses to report clean when the path
|
|
1314
|
+
# does not resolve — so a rename reds the gate instead of retiring it.
|
|
1315
|
+
|
|
1316
|
+
# check_new_adr_evidence is DELIBERATELY NOT REGISTERED here, following this
|
|
1317
|
+
# file's own two precedents rather than breaking them.
|
|
1318
|
+
#
|
|
1319
|
+
# It is diff-scoped: its corpus is the set of decision records ADDED on the
|
|
1320
|
+
# branch (`git diff --diff-filter=A` over `docs/decisions/ADR-*.md` and
|
|
1321
|
+
# `docs/adrs/<area>/NNNN-*.md`), so ZERO is the honest reading on almost every
|
|
1322
|
+
# run and any floor above 0 reds every branch that adds no ADR. A
|
|
1323
|
+
# `min_scanned: 0` row is the false-count shape this file's header rejects in
|
|
1324
|
+
# as many words, and `lint_evidence_artifacts` and
|
|
1325
|
+
# `check_rule_projection_integrity` both hit this exact wall and resolved it by
|
|
1326
|
+
# staying unregistered. A row was written first and then withdrawn: the
|
|
1327
|
+
# argument for it was that a registered gate at least runs under CI-identical
|
|
1328
|
+
# argv, and that is real but it is not worth being the one instance that
|
|
1329
|
+
# introduces the shape two neighbours were excluded to avoid. Three precedents
|
|
1330
|
+
# agreeing is a convention; two agreeing and one defecting is drift.
|
|
1331
|
+
#
|
|
1332
|
+
# It is NOT unwatched. `task check-new-adr-evidence` and the
|
|
1333
|
+
# `New accepted ADRs disclose their evidence` step in rule-backstops.yml both
|
|
1334
|
+
# run it, so a broken gate fails there.
|
|
1335
|
+
#
|
|
1336
|
+
# And it is NOT unproven, which is the part a floor could never have supplied.
|
|
1337
|
+
# This gate's normal reading is zero added records — precisely the state where
|
|
1338
|
+
# a working gate and a completely broken one emit identical output
|
|
1339
|
+
# (`scanned: 0`, green), so no floor separates them at any value. `--self-test`
|
|
1340
|
+
# does: seven cases, four rejecting, each building a throwaway repo and driving
|
|
1341
|
+
# the real CLI with `--base <sha>`, including the case an `authority_basis:
|
|
1342
|
+
# owner_intent` escape must NOT buy (that field governs authority, never
|
|
1343
|
+
# disclosure). Sabotage-verified — with the `## Evidence` check removed the
|
|
1344
|
+
# self-test exits 1 and names the two cases that stopped firing.
|
|
1345
|
+
#
|
|
1346
|
+
# What is LOST, stated rather than implied: no minimum scan is held against
|
|
1347
|
+
# this gate by this manifest, so a change that silently narrowed its path
|
|
1348
|
+
# regexes to nothing would pass here. The self-test is what catches that, and
|
|
1349
|
+
# it is a test rather than a manifest floor — it runs when someone runs it.
|
|
1350
|
+
|
|
1351
|
+
# adr/evidence_census is DELIBERATELY NOT REGISTERED here either, for the
|
|
1352
|
+
# same structural reason and with a different cost.
|
|
1353
|
+
#
|
|
1354
|
+
# `matchesGatePattern` classifies on a name PREFIX
|
|
1355
|
+
# (`lint|check|audit|skill|verify_`) and `evidence_census.ts` carries neither,
|
|
1356
|
+
# so a row here would red `gate_population.test.ts` exactly as the
|
|
1357
|
+
# `adr_cite_check` row did. The block below weighs the three fixes for that
|
|
1358
|
+
# case and they apply unchanged: widening the pattern, renaming the script, or
|
|
1359
|
+
# inverting the classification to be manifest-driven.
|
|
1360
|
+
#
|
|
1361
|
+
# What is DIFFERENT, and better than the adr_cite_check case: the census is not
|
|
1362
|
+
# unwatched. `task check-adr-evidence-census` regenerates it to a temp path and
|
|
1363
|
+
# diffs against the committed artifact, wired in the `ci` chain and as the
|
|
1364
|
+
# `ADR evidence census up to date` step in rule-backstops.yml, so a corpus that
|
|
1365
|
+
# drifted from the artifact fails there instead of here. The census emits a
|
|
1366
|
+
# `scanned:` line and adopts the ledger, so what is lost is only the MINIMUM
|
|
1367
|
+
# SCAN FLOOR — a change that narrowed its corpus to zero AND regenerated the
|
|
1368
|
+
# artifact to match would pass both. Stated rather than implied, because the
|
|
1369
|
+
# drift check is a byte-comparison and byte-agreement on an empty corpus is
|
|
1370
|
+
# still agreement. Closing it properly is the same rename, in the same change
|
|
1371
|
+
# that renames adr_cite_check.
|
|
1372
|
+
|
|
1373
|
+
# adr_cite_check is DELIBERATELY NOT REGISTERED here, and the reason is a
|
|
1374
|
+
# disagreement between two gates over the same file rather than an oversight.
|
|
1375
|
+
#
|
|
1376
|
+
# The script is gate-shaped by behaviour: it emits one `scanned:` line, adopts
|
|
1377
|
+
# the ledger, asserts its scan scope, and runs in CI as `ADR citations resolve`
|
|
1378
|
+
# (rule-backstops.yml) plus `task check-adr-citations`. So it certifies
|
|
1379
|
+
# something and can lie about it, which is this manifest's own criterion.
|
|
1380
|
+
#
|
|
1381
|
+
# But `gate_population.matchesGatePattern` classifies structurally, on a NAME
|
|
1382
|
+
# PREFIX (`lint|check|audit|skill|verify_`), and `adr_cite_check.ts` carries
|
|
1383
|
+
# `check` as a suffix. Registering it made `gate_population.test.ts` red:
|
|
1384
|
+
# "manifest lists adr_cite_check, population does not". The two gates read the
|
|
1385
|
+
# same file and disagree.
|
|
1386
|
+
#
|
|
1387
|
+
# Three fixes were weighed and each was worse than the gap:
|
|
1388
|
+
# - widening the pattern to a `_check$` suffix pulls in four unrelated
|
|
1389
|
+
# scripts (bench_drift_check, worktree_cleanup_check, update_check,
|
|
1390
|
+
# cmd_settings_check), forcing them into the ledger contract and reddening
|
|
1391
|
+
# the completeness ratchet for work nobody asked for;
|
|
1392
|
+
# - renaming the script to `check_adr_citations.ts` is the convention-conform
|
|
1393
|
+
# answer and touches 26 files, including archived review artefacts and a
|
|
1394
|
+
# committed diff.patch that must not be rewritten;
|
|
1395
|
+
# - manifest-driven classification is explicitly rejected by
|
|
1396
|
+
# gate_population.ts's own header (a new gate lands before anyone
|
|
1397
|
+
# registers it, so that inverts the real dependency).
|
|
1398
|
+
#
|
|
1399
|
+
# So the row is dropped and the floor is unregistered. What is LOST is stated
|
|
1400
|
+
# rather than implied: the gate runs, but nothing holds it to a minimum scan,
|
|
1401
|
+
# so a future change that silently narrowed its corpus to zero would pass. The
|
|
1402
|
+
# honest close is the rename, in its own change, where 26 files of churn are
|
|
1403
|
+
# the subject rather than a side effect.
|