@event4u/agent-config 8.7.0 → 8.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 +52 -0
- package/CONTRIBUTING.md +25 -0
- package/README.md +7 -4
- package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +1 -1
- package/dist/agent-src/contexts/execution/orchestration-benchmark-gate.md +28 -16
- package/dist/agent-src/contexts/execution/orchestration-telemetry.md +15 -0
- package/dist/agent-src/rules/active-remediation.md +92 -0
- package/dist/agent-src/rules/broken-access-control.md +106 -0
- package/dist/agent-src/rules/communication-through-line.md +42 -0
- package/dist/agent-src/rules/decision-revisit-gate.md +8 -0
- package/dist/agent-src/rules/minimal-safe-diff.md +18 -1
- package/dist/agent-src/rules/prefer-enums-over-literals.md +65 -0
- package/dist/agent-src/rules/senior-engineering-discipline.md +82 -0
- package/dist/agent-src/skills/ai-code-blindspots/SKILL.md +105 -0
- package/dist/agent-src/skills/ai-code-blindspots/evals/triggers.json +52 -0
- package/dist/agent-src/skills/authz-review/SKILL.md +21 -4
- package/dist/agent-src/skills/dependency-upgrade/SKILL.md +20 -0
- package/dist/agent-src/skills/frontend-render-security/SKILL.md +104 -0
- package/dist/agent-src/skills/frontend-render-security/evals/triggers.json +52 -0
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +7 -0
- package/dist/agent-src/skills/supply-chain-intake/SKILL.md +100 -0
- package/dist/agent-src/skills/supply-chain-intake/evals/triggers.json +52 -0
- package/dist/agent-src/skills/testing-anti-patterns/SKILL.md +43 -2
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/roadmaps.md +24 -0
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +195 -15
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +3 -3
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +13 -5
- package/dist/discovery/trust-report.md +11 -11
- package/dist/discovery/workspaces.json +12 -4
- package/dist/install/install.mjs +5 -2
- package/dist/mcp/awesome-mcp-servers.row.md +1 -1
- package/dist/mcp/mcp-cloudflare-catalogue.json +1 -1
- package/dist/mcp/registry-manifest.json +4 -4
- package/dist/router.json +1 -1
- package/dist/server/schemas/settings.js +2 -1
- package/dist/server/schemas/settings.js.map +1 -1
- package/docs/CLAIMS.md +30 -2
- package/docs/architecture.md +2 -2
- package/docs/catalog.md +14 -0
- package/docs/contracts/mcp-tool-inventory.md +31 -30
- package/docs/decisions/ADR-105-automatic-subagent-orchestration.md +6 -0
- package/docs/decisions/ADR-116-memory-tripwire-activation-path.md +2 -2
- package/docs/decisions/ADR-117-subagents-auto-default-on.md +88 -0
- package/docs/decisions/INDEX.md +1 -0
- package/docs/experiences/content_creator.md +2 -0
- package/docs/experiences/finance.md +2 -0
- package/docs/experiences/founder.md +2 -0
- package/docs/experiences/ops.md +2 -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/guidelines/agent-infra/memory-access.md +12 -0
- package/docs/proof.md +45 -3
- package/docs/release-runbook.md +138 -0
- package/docs/second-brain-scope.md +73 -0
- package/docs/succession.md +80 -0
- package/package.json +2 -2
- package/src/config/agent-settings.template.yml +25 -6
- package/src/scripts/_lib/orchestration_gate.ts +12 -8
- package/src/scripts/_lib/orchestration_savings.ts +127 -0
- package/src/scripts/build_proof.ts +38 -0
- package/src/scripts/chat_history.ts +79 -7
- package/src/scripts/domain_soundness_status.ts +236 -0
- package/src/scripts/generate_index.ts +14 -0
- package/src/scripts/hot_context_hook.ts +47 -2
- package/src/scripts/lint_behavioural_eval_freshness.ts +140 -0
- package/src/scripts/mcp_server/consumer_tool_catalog.json +22 -3
- package/src/scripts/mcp_server/tools.ts +159 -1
- package/src/scripts/memory_lookup.ts +184 -6
- package/src/scripts/memory_replay.ts +285 -0
- package/src/scripts/orchestration_savings_report.ts +100 -0
- package/src/scripts/schemas/domain-truth.schema.json +94 -0
- package/src/scripts/schemas/evals.schema.json +113 -0
- package/src/scripts/second_brain_score.ts +186 -0
- package/src/scripts/session_memory_index.ts +94 -0
- package/src/scripts/skill_eval_coverage.ts +318 -0
- package/src/server/schemas/settings.ts +5 -2
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
},
|
|
7
7
|
"metadata": {
|
|
8
8
|
"description": "Bootstrap shim for the event4u agent-config suite. This plugin ships ONLY the dispatcher hooks plus one install-pointer skill — ALL content (skills, rules, commands) is installed via `npx -y @event4u/agent-config init`, which writes the file projection AND registers the same hooks in ~/.claude/settings.json. DEPRECATED as a content channel; kept so the marketplace listing stays discoverable and existing installs keep working hooks.",
|
|
9
|
-
"version": "8.
|
|
9
|
+
"version": "8.8.0",
|
|
10
10
|
"keywords": [
|
|
11
11
|
"agent-config",
|
|
12
12
|
"skills",
|
package/CHANGELOG.md
CHANGED
|
@@ -989,6 +989,58 @@ our recommendation order, not its support status.
|
|
|
989
989
|
> that forces a new era split (`# Era: 8.2.x`, etc.) — see
|
|
990
990
|
> [`docs/contracts/CHANGELOG-conventions.md § Era splits`](docs/contracts/CHANGELOG-conventions.md).
|
|
991
991
|
|
|
992
|
+
## [8.8.0](https://github.com/event4u-app/agent-config/compare/8.7.0...8.8.0) (2026-07-09)
|
|
993
|
+
|
|
994
|
+
### Features
|
|
995
|
+
|
|
996
|
+
* **rules:** security & quality hardening governance layer ([2574ce8](https://github.com/event4u-app/agent-config/commit/2574ce8f243763e06e62ad82e58413d182964a50))
|
|
997
|
+
* **orchestration:** token-savings report over orchestration telemetry ([60b90a2](https://github.com/event4u-app/agent-config/commit/60b90a253efe26810a349a930d8fd6fdf02a3d37))
|
|
998
|
+
* **subagents:** default subagents.auto to `on` on subagent-capable hosts ([bc3eea5](https://github.com/event4u-app/agent-config/commit/bc3eea554e06cbcc9013145143fce93a1a1adb53))
|
|
999
|
+
* **bus-factor:** CODEOWNERS + self-imposed-gate CONTRIBUTING section ([ec9b93e](https://github.com/event4u-app/agent-config/commit/ec9b93ebe94f33aecf6ddb00b72dbfb60b2e0c37))
|
|
1000
|
+
* **second-brain:** deterministic multi-session recall corpus + scorer ([5f09fff](https://github.com/event4u-app/agent-config/commit/5f09ffff2d4090ed6761f37d55a8bb0a73b99333))
|
|
1001
|
+
* **domain-soundness:** domain-truth fixture schema + validation-status ratchet ([bd67c4d](https://github.com/event4u-app/agent-config/commit/bd67c4dec9de9691eea2b1367807a4e190db5db8))
|
|
1002
|
+
* **evals:** staleness lint + wire the coverage ratchet into CI ([886bf25](https://github.com/event4u-app/agent-config/commit/886bf25fedcaface708ee3f8be17135d8be2e742))
|
|
1003
|
+
* **evals:** behavioural-eval schema + per-tier coverage metric + ratchet floor ([2e303f6](https://github.com/event4u-app/agent-config/commit/2e303f66d076355434ff720b6d81ac3f3021b22e))
|
|
1004
|
+
* **memory:** opt-in session-start index + FTS5/AST backlog ledger ([bb15b21](https://github.com/event4u-app/agent-config/commit/bb15b21fb334d7c44896b7ef4c340c0396f0c6c4))
|
|
1005
|
+
* **memory:** catalog discipline, history timeline anchor, chunk index flags ([3cce078](https://github.com/event4u-app/agent-config/commit/3cce0789f48966fe31e8fad1ad63ae2477c53259))
|
|
1006
|
+
* **memory:** index/detail split + memory_get batch fetch (Phase 1) ([36547c8](https://github.com/event4u-app/agent-config/commit/36547c88452c99eb02d7c2db61ce9556701db80d))
|
|
1007
|
+
* **memory:** Phase 0 replay substrate for the retrieval-economy gate ([6d05daf](https://github.com/event4u-app/agent-config/commit/6d05dafa35ae38b4c4d97cd17a155c1e4bbc801e))
|
|
1008
|
+
|
|
1009
|
+
### Bug Fixes
|
|
1010
|
+
|
|
1011
|
+
* **rules:** apply council-adjudicated review fixes ([d6d818a](https://github.com/event4u-app/agent-config/commit/d6d818a8bfb79c6862488eb367f4f3e92f7d7aa6))
|
|
1012
|
+
* **rules:** satisfy skill-lint, schema, and proof-check gates ([ea551cc](https://github.com/event4u-app/agent-config/commit/ea551cc5c9efb21ab6453948f97848557d98ae1f))
|
|
1013
|
+
* **orchestration:** guard undefined argv in savings-report parseArgs ([cf2539e](https://github.com/event4u-app/agent-config/commit/cf2539e73ac7e7edbaee206bcd09e03032986618))
|
|
1014
|
+
* **mcp:** cast validated depth args to number for tsc ([cc5a8a4](https://github.com/event4u-app/agent-config/commit/cc5a8a4ac80ac245ec2b30fa4223d1888788e475))
|
|
1015
|
+
|
|
1016
|
+
### Documentation
|
|
1017
|
+
|
|
1018
|
+
* **orchestration:** document the savings report + the no-percentage limit ([d29a5d1](https://github.com/event4u-app/agent-config/commit/d29a5d10411c3507d6fb035ac44959ee2a738435))
|
|
1019
|
+
* **adoption:** link the deployed docs site + surface the 30-second wedge ([eb74680](https://github.com/event4u-app/agent-config/commit/eb74680bec665c422e226ac8c5e8458c8279539e))
|
|
1020
|
+
* **adr:** ADR-117 flip subagents.auto default to on; amend ADR-105, supersede verdict ([0b5879c](https://github.com/event4u-app/agent-config/commit/0b5879c3f25014c54779e959e16282ac66d4ae4d))
|
|
1021
|
+
* **bus-factor:** bind the honest bus-factor to CLAIMS ([6bbbda4](https://github.com/event4u-app/agent-config/commit/6bbbda4d841f084c27c5a8f34bd10171429bc684))
|
|
1022
|
+
* **bus-factor:** inheritable release runbook + succession doc ([7d05577](https://github.com/event4u-app/agent-config/commit/7d05577f32c154332fb8bdf90833e8e7acf7f704))
|
|
1023
|
+
* **second-brain:** honest scope vs human-PKM + unproven-lift CLAIMS gate ([b9dc934](https://github.com/event4u-app/agent-config/commit/b9dc9347661237c24cdadd5ca454ed07acbf9409))
|
|
1024
|
+
* **domain-soundness:** label the domains unvalidated + gate the provenance claim ([7221662](https://github.com/event4u-app/agent-config/commit/72216625a559818196441349501af3b65c4be3ce))
|
|
1025
|
+
* **evals:** publish the honest coverage baseline + label the long tail ([299a7fe](https://github.com/event4u-app/agent-config/commit/299a7fe74360a8df5b7d46c026be65b501685ff0))
|
|
1026
|
+
* **memory:** Phase 1b honest null — default flip falsified at current scale ([938aab2](https://github.com/event4u-app/agent-config/commit/938aab2f5d6dcf43fd82738025fe309d5cb7ad91))
|
|
1027
|
+
|
|
1028
|
+
### CI
|
|
1029
|
+
|
|
1030
|
+
* **second-brain:** wire the recall-scorer dry-run into ci + ci-strict ([7da6d01](https://github.com/event4u-app/agent-config/commit/7da6d010f40793e31a9b3f891a5e08aa2afe184c))
|
|
1031
|
+
* **domain-soundness:** wire the validation-status ratchet into ci + ci-strict ([7ae10c2](https://github.com/event4u-app/agent-config/commit/7ae10c2cd4d36e65db3a52c8c68b824200c3f9c6))
|
|
1032
|
+
|
|
1033
|
+
### Chores
|
|
1034
|
+
|
|
1035
|
+
* **generated:** regenerate counts, router, and pack manifest ([f141060](https://github.com/event4u-app/agent-config/commit/f141060e9da2f4f0a97a257d2786dd42fdf2ee0f))
|
|
1036
|
+
* **roadmap:** adoption Phase-0 site-link quick-win landed; rest positioning/human-gated ([de27276](https://github.com/event4u-app/agent-config/commit/de27276b06b3969a8ea8a22ed5327385aa3ff582))
|
|
1037
|
+
* **roadmap:** bus-factor inheritability slice landed; gate + admin deferred ([8bf79f5](https://github.com/event4u-app/agent-config/commit/8bf79f5dd3e9dcd940acce7c56eaad978d2525f7))
|
|
1038
|
+
* **roadmap:** second-brain-delta-proof P1 rig + P3 gate landed; P2 run deferred ([e01ec9e](https://github.com/event4u-app/agent-config/commit/e01ec9e9691fa5d19390fa3b187bafbef3e34618))
|
|
1039
|
+
* **roadmap:** domain-soundness P1/P3-gate/P4-labeling landed; P2 open on domain competence ([9a786d4](https://github.com/event4u-app/agent-config/commit/9a786d4cb2b0dc469c3b2967e8bc360e9877ec79))
|
|
1040
|
+
* **roadmap:** skill-eval-coverage P1/P3/P4 landed; P2 open on human gate ([a4c526d](https://github.com/event4u-app/agent-config/commit/a4c526d43a459bb86d78dcf2d07e3dc2d44b6828))
|
|
1041
|
+
|
|
1042
|
+
Tests: 7027 (+78 since 8.7.0)
|
|
1043
|
+
|
|
992
1044
|
## [8.7.0](https://github.com/event4u-app/agent-config/compare/8.6.0...8.7.0) (2026-07-08)
|
|
993
1045
|
|
|
994
1046
|
### Features
|
package/CONTRIBUTING.md
CHANGED
|
@@ -93,6 +93,25 @@ task lint-skills # ./scripts-run src/scripts/skill_linter --all
|
|
|
93
93
|
- Open the PR against `main` with a short description of the change,
|
|
94
94
|
motivation, and any notes for reviewers.
|
|
95
95
|
|
|
96
|
+
## Reviewability and the self-imposed gate
|
|
97
|
+
|
|
98
|
+
This is a governance standard, so the maintainer holds themselves to the same
|
|
99
|
+
gate as any contributor — the point is that even a solo merge goes **through**
|
|
100
|
+
the review floor, not around it.
|
|
101
|
+
|
|
102
|
+
- [`.github/CODEOWNERS`](.github/CODEOWNERS) routes review on the sensitive
|
|
103
|
+
surfaces (kernel rules, router compiler, install, hooks, claims/proof
|
|
104
|
+
generators, release pipeline, schemas). Branch protection is configured to
|
|
105
|
+
require Code-Owner review on those paths (maintainer, in GitHub → Settings →
|
|
106
|
+
Rules; source of truth: [`docs/contracts/branch-protection-policy.md`](docs/contracts/branch-protection-policy.md)).
|
|
107
|
+
- **Honest bound:** an AI adversarial-review / security gate (when enabled)
|
|
108
|
+
raises the floor and catches regressions and claim-drift, but it is **not**
|
|
109
|
+
independent human review. The bus-factor is tracked truthfully in
|
|
110
|
+
[`docs/succession.md`](docs/succession.md) — a bus-factor of 1 stated plainly
|
|
111
|
+
beats one implied to be more.
|
|
112
|
+
- A realistic second-reviewer on-ramp starts small (docs/claims or a single
|
|
113
|
+
pack), never "co-maintain the kernel on day one".
|
|
114
|
+
|
|
96
115
|
## Adding or editing skills, rules, and commands
|
|
97
116
|
|
|
98
117
|
- Skills and rules live in `src/skills/` and `src/rules/`; commands in
|
|
@@ -276,6 +295,12 @@ which never reach a consumer.
|
|
|
276
295
|
|
|
277
296
|
### Release process
|
|
278
297
|
|
|
298
|
+
> **Inheritable runbook:** the exact, reproducible steps a second maintainer
|
|
299
|
+
> can follow cold — both entry points, the manual approval checkpoint, and
|
|
300
|
+
> recovery — live in [`docs/release-runbook.md`](docs/release-runbook.md), with
|
|
301
|
+
> the secret/operator-gated dependencies in [`docs/succession.md`](docs/succession.md).
|
|
302
|
+
> The summary below is orientation; the runbook is the source of truth.
|
|
303
|
+
|
|
279
304
|
Releases are driven by a single command that owns the entire pipeline from
|
|
280
305
|
version bump to npm publish:
|
|
281
306
|
|
package/README.md
CHANGED
|
@@ -4,19 +4,21 @@
|
|
|
4
4
|
|
|
5
5
|
[](https://github.com/event4u-app/agent-config/actions/workflows/smoke.yml) [](https://github.com/event4u-app/agent-config/actions/workflows/smoke-public-install.yml) [](https://www.npmjs.com/package/@event4u/agent-config) [](https://glama.ai/mcp/servers/event4u-app/agent-config)
|
|
6
6
|
|
|
7
|
-
[](dist/agent-src/skills/) [](dist/agent-src/rules/) [](dist/agent-src/commands/) [](docs/guidelines/) [](dist/agent-src/personas/) [](dist/agent-src/personas/advisors/)
|
|
8
8
|
|
|
9
9
|
> **Choose your experience — developer · founder · content · agency · finance · ops. Add packs. Get a focused command set, not a 500-artefact dump.** Bring your own AI provider.
|
|
10
10
|
|
|
11
|
+
**Try it in 30 seconds** — drop one read-only subagent into any repo and watch it gate "done": `@production-validator check this branch is actually done`. No wizard, no lock-in, nothing else installed — the [30-second wedge ↓](#quickstart) is the whole first step. Full docs: **[event4u-app.github.io/agent-config](https://event4u-app.github.io/agent-config)**.
|
|
12
|
+
|
|
11
13
|
**Every public claim in this README is machine-checked — [verify it yourself](docs/proof.md).** In a market that runs on unbacked headline numbers, this one binds each claim to resolvable evidence or fails its own build.
|
|
12
14
|
|
|
13
|
-
**
|
|
15
|
+
**267 skills, 172 commands, 100 governed rules** — plus a capability router that loads the right skill on intent, and multi-agent orchestration with consensus review. The whole layer is compiled into 7+ host agents (Claude Code, Cursor, Augment, Cline, Windsurf, Copilot, Gemini) with **zero runtime daemon**.<!-- claim:no-runtime-daemon --> Six role-shaped entry paths sit on top, so any host becomes a reliable team member — without locking you to a single model or vendor.
|
|
14
16
|
|
|
15
17
|
### What's different
|
|
16
18
|
|
|
17
19
|
It is both deep **and** disciplined — and honest about what it deliberately is not:
|
|
18
20
|
|
|
19
|
-
- **Depth that routes itself** —
|
|
21
|
+
- **Depth that routes itself** — 267 skills + 172 commands, with a capability router that loads the right one on intent, not a 500-artefact context dump.
|
|
20
22
|
- **Governance on every host** — rules compiled into each tool's native format at projection time; deterministic runtime hooks added on hook-capable hosts. This config-space, host-agnostic governance is the moat ([the governance advantage](docs/governance-advantage.md) · [enforcement by host](docs/enforcement-by-host.md)).
|
|
21
23
|
- **Surgical uninstall** — removes only its own keys from a shared host config (matched by JSON-pointer + SHA-256), never a neighbour tool's entries.<!-- claim:surgical-uninstall -->
|
|
22
24
|
- **Pack-scoped install** — writes the active pack only, not a 500-artefact dump.
|
|
@@ -118,7 +120,8 @@ is generated from source: a claim→evidence table (every public claim binds to
|
|
|
118
120
|
resolvable pointer, or CI fails), honest-null benchmarks *including the runs where
|
|
119
121
|
the package changed nothing*, and a "verify it yourself" block you run on a fresh
|
|
120
122
|
checkout. The proof page fails CI if it drifts from its sources — reproducibility
|
|
121
|
-
is the proof.
|
|
123
|
+
is the proof. Browse it on the deployed docs site:
|
|
124
|
+
[event4u-app.github.io/agent-config](https://event4u-app.github.io/agent-config).
|
|
122
125
|
|
|
123
126
|
Audit-disciplined by construction — every memory consult, decision
|
|
124
127
|
key, and hook concern lands in `agents/runtime/state/` so you can replay it.
|
|
@@ -12,7 +12,7 @@ whether dispatch is physically possible on the host).
|
|
|
12
12
|
| Key | Default | Purpose |
|
|
13
13
|
|---|---|---|
|
|
14
14
|
| `subagents.enabled` | `true` | Global master switch. `false` = the whole layer is off — the canonical kill-switch. No auto-dispatch, no routing, everything runs in-session. |
|
|
15
|
-
| `subagents.auto` | `
|
|
15
|
+
| `subagents.auto` | `on` | Auto-dispatch mode: `off` \| `ask` \| `on`. Default `on` on subagent-capable hosts (flipped from `ask` 2026-07-09, ADR-117), `off` elsewhere. |
|
|
16
16
|
| `subagents.downshift` | `true` | Route delegable sub-tasks to the lowest-capable tier (Phase 2). |
|
|
17
17
|
| `subagents.quota_arbitrage` | `true` | Prefer a separate-quota-pool model where the host manifest allows it (Phase 2 bonus). |
|
|
18
18
|
| `subagents.model_map` | `{}` | Optional per-tier model override for downshift routing. |
|
|
@@ -1,9 +1,19 @@
|
|
|
1
|
-
# Orchestration Benchmark &
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
# Orchestration Benchmark & Demotion Gate (Phase 6 → telemetry-demotion)
|
|
2
|
+
|
|
3
|
+
Originally the falsification gate the auto-orchestration roadmap was built
|
|
4
|
+
around: shipped default for `subagents.auto` would flip toward `on` only on a
|
|
5
|
+
benchmark proving a net win at held quality.
|
|
6
|
+
|
|
7
|
+
**As of 2026-07-09 the shipped default IS `on`** on subagent-capable hosts
|
|
8
|
+
(ADR-117; [`orchestration-default-flip-verdict`](../../../../agents/settings/contexts/orchestration-default-flip-verdict.md)
|
|
9
|
+
§ 2026-07-09). Flipped on a **bounded-downside re-evaluation**, not a passed
|
|
10
|
+
benchmark: rigorous paired bench:ab not producible here (no runtime executing
|
|
11
|
+
model `Task`/`Agent` calls), win-validation deadlocked (telemetry needs `on`,
|
|
12
|
+
`on` gated on telemetry). Re-eval broke the deadlock — downside of `on` is
|
|
13
|
+
structurally small (delegable slices cost-routed to cheapest tier,
|
|
14
|
+
classification fires only on real structural signals, every return verified) →
|
|
15
|
+
`on` gathers realized telemetry responsibly. This gate now governs
|
|
16
|
+
**demotion**: measured regression flips default back to `ask`.
|
|
7
17
|
|
|
8
18
|
## Measurement — pin the method
|
|
9
19
|
|
|
@@ -30,18 +40,20 @@ HONEST-NULL EXIT: no win, or quality regressed → KEEP the conservative default
|
|
|
30
40
|
|
|
31
41
|
`gateVerdict()` encodes pass = `net_win && quality_held`.
|
|
32
42
|
|
|
33
|
-
## Default
|
|
43
|
+
## Default state + demotion — host-gated
|
|
34
44
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
45
|
+
Shipped default for `subagents.auto` is `on` on hosts whose manifest reports
|
|
46
|
+
`subagent_spawn: true` (`off` elsewhere) — set directly in
|
|
47
|
+
`src/config/agent-settings.template.yml`. `resolveShippedDefault()` remains the
|
|
48
|
+
host-gated resolver, now serving **demotion**: fed a `fail` verdict from
|
|
49
|
+
accumulated real-world orchestration telemetry, resolves back to `ask`
|
|
50
|
+
(conservative). A `pass` keeps `on`. Demotion path is a one-line edit,
|
|
51
|
+
host-gated by the manifest at runtime.
|
|
41
52
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
53
|
+
The 2026-07-09 flip reconciles the user's "default on" goal with the council's
|
|
54
|
+
"prove-first": rather than wait on a benchmark that cannot be produced here,
|
|
55
|
+
`on` ships because its downside is bounded and reversible, and realized
|
|
56
|
+
telemetry is now free to accrue and drive demotion if it regresses.
|
|
45
57
|
|
|
46
58
|
## Reproducibility
|
|
47
59
|
|
|
@@ -87,6 +87,21 @@ capture path (decided 2026-06-30, maintainer decision; see
|
|
|
87
87
|
response length (chars / 4 ≈ tokens). Set `token_delta_provenance:
|
|
88
88
|
"estimated"`. Lossy; measured always preferred.
|
|
89
89
|
|
|
90
|
+
## Savings report
|
|
91
|
+
|
|
92
|
+
Aggregate accumulated telemetry into a token-savings report:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
./scripts-run src/scripts/orchestration_savings_report [--dir <path>] [--format text|json]
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Sums `token_delta` across dispatches (negative = net saved); splits by
|
|
99
|
+
provenance (measured vs estimated), `tier_chosen`, `task_class`. Reports
|
|
100
|
+
**ABSOLUTE net tokens saved, never a percentage**: telemetry records net delta,
|
|
101
|
+
not the absolute in-session baseline → "% of session saved" not derivable. A
|
|
102
|
+
percentage needs an additive absolute-baseline field (deferred follow-up).
|
|
103
|
+
Reader: [`src/scripts/_lib/orchestration_savings.ts`](../../../../src/scripts/_lib/orchestration_savings.ts).
|
|
104
|
+
|
|
90
105
|
## Related
|
|
91
106
|
|
|
92
107
|
- [`audit-log-v1`](../../../../docs/contracts/audit-log-v1.md) — the frozen
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: "auto"
|
|
3
|
+
tier: "2b"
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
description: "Spotted an issue while working (security gap, missing test, bad code, duplication, stale idiom) — never ignore; fix small+aligned inline, ask on bigger, propose a follow-up PR for many"
|
|
6
|
+
triggers:
|
|
7
|
+
- intent: "spotted an unrelated issue while working"
|
|
8
|
+
- intent: "found legacy or duplicated code"
|
|
9
|
+
- keyword: "refactor"
|
|
10
|
+
- keyword: "duplicate"
|
|
11
|
+
- keyword: "legacy"
|
|
12
|
+
- keyword: "deprecated"
|
|
13
|
+
- keyword: "modernize"
|
|
14
|
+
- keyword: "upgrade"
|
|
15
|
+
- keyword: "cleanup"
|
|
16
|
+
- keyword: "technical debt"
|
|
17
|
+
workspaces: [engineering]
|
|
18
|
+
packs: [engineering-base]
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
# Active Remediation
|
|
22
|
+
|
|
23
|
+
The user doesn't see the code at the spot you're editing — you do. So this package guides the agent to **actively improve** what it touches: don't accept legacy, debt, security gaps, or duplication as given. But active improvement is bounded — never the scope creep `minimal-safe-diff` exists to stop. The rule is a **ladder**: act by size and alignment, and **never silently ignore** a real issue.
|
|
24
|
+
|
|
25
|
+
## The Iron Law
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
NEVER IGNORE A REAL ISSUE YOU SPOT — AT MINIMUM, NOTE IT.
|
|
29
|
+
SMALL + TASK-ALIGNED → FIX IT NOW, IN THE SAME CHANGE, WITH ITS TEST.
|
|
30
|
+
BIGGER OR DIVERGENT → NOTE IT, FINISH THE TASK, THEN ASK — NEVER MID-FLOW.
|
|
31
|
+
TOO MANY → PROPOSE ONE OR MORE SEPARATE FOLLOW-UP PRs THE USER REVIEWS.
|
|
32
|
+
A LIVE SECURITY / DATA-EXPOSURE GAP IS NEVER MERELY "NOTED FOR LATER".
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## What to remediate
|
|
36
|
+
|
|
37
|
+
Security gaps (broken access control, injection, secrets, missing authz — see `broken-access-control`) · missing/weak test coverage · bad code (dead code, silent error-swallow, unguarded edge cases) · **duplication** (same/near-same logic repeated instead of one method/abstraction) · **stale version-idioms** (code for an older language/framework version than the project runs).
|
|
38
|
+
|
|
39
|
+
## The ladder — classify, then act
|
|
40
|
+
|
|
41
|
+
### Fix now (autonomous, inline) — a bounded amendment to `minimal-safe-diff`
|
|
42
|
+
|
|
43
|
+
Allowed **only** when ALL hold — the testable "small + task-aligned" definition:
|
|
44
|
+
- **Same request path / module** as the current task (not an unrelated feature).
|
|
45
|
+
- **≤ ~10 changed lines** in one production file plus its test file — no wider cross-file ripple.
|
|
46
|
+
- **No public-API / response-shape change**, no new parameter.
|
|
47
|
+
- **No dependency bump, no migration, no data change.**
|
|
48
|
+
- **Its verification ships in the same commit** — the security fix's negative test, the correctness fix's case.
|
|
49
|
+
|
|
50
|
+
Under those constraints the fix is auditable in the same diff and is *not* scope creep — it corrects a boundary the agent touched. Anything outside them → **note + ask**, never auto. (`minimal-safe-diff` still governs the rest: no reformatting, no opportunistic refactor, no drive-by rename.)
|
|
51
|
+
|
|
52
|
+
### Note + ask (batched)
|
|
53
|
+
|
|
54
|
+
Bigger, or diverges from the task → do **not** refactor inline, do **not** interrupt the flow. Note the site (file:line + issue). Surface the batch as **one** numbered-options prompt (`user-interaction`, one recommendation line) **after the task is delivered** — or mid-work only when the flow makes it natural. Each option carries a real trade-off (`no-cheap-questions`). Refactor only on an explicit yes, as a separate scoped change (`scope-control`, `downstream-changes`).
|
|
55
|
+
|
|
56
|
+
### Propose a follow-up PR (many spots)
|
|
57
|
+
|
|
58
|
+
Too many to fold in without blowing the current diff's scope → propose **one or more separate follow-up PRs** (or a roadmap under `agents/roadmaps/`, using the shared-prefix convention) so the user reviews before merge. Creating the PR/roadmap is **permission-gated** — propose, get a yes, then create (`scope-control`, `commit-policy`).
|
|
59
|
+
|
|
60
|
+
## Version-gated modernization
|
|
61
|
+
|
|
62
|
+
Update stale idioms to the version the project **actually runs** — only when that version is **verified**:
|
|
63
|
+
- **Establish the version first** from the manifest constraint (`composer.json` `require`, `package.json` `engines`, `.tool-versions`, lockfile) — use the **lowest** bound; on an ambiguous/monorepo range, ask once. **Unknown version → do not touch** (must fit the project structure — the `source-discovery` gate).
|
|
64
|
+
- **Syntax-only, behavior-preserving idioms** (e.g. `array()` → `[]`, `isset($x)?$x:$d` → `$x ?? $d`, concat → template) provably equivalent → treat as a small fix (auto per the ladder).
|
|
65
|
+
- **Behavioral changes** (`readonly`/typed properties, new semantics) and **any dependency/version bump** → **ask only**, never auto (a version bump stays under `minimal-safe-diff`'s no-dependency-bump prohibition; a pure syntax idiom is categorically different).
|
|
66
|
+
|
|
67
|
+
## Live-security carve-out (priority)
|
|
68
|
+
|
|
69
|
+
A **live cross-user / cross-tenant data exposure** (`broken-access-control`) is not "note for later": a potential GDPR-notifiable breach (Art. 33, 72 h from discovery). Meets the fix-now bar → fix now with its negative test. Otherwise → **stop and surface it immediately** (a safety surface, visible even under an autonomous mandate — like the `no-pr-progress-comments` safety carve-out). Never defer silently, never look away.
|
|
70
|
+
|
|
71
|
+
## Guardrails — don't become a nagging machine
|
|
72
|
+
|
|
73
|
+
- Subordinate to `no-cheap-questions` (self-check items 3 & 14 — real trade-off, not a disguised continuation/commit ask), `autonomous-execution` (the end-of-session batch must not read as "shall I continue?"), `user-interaction`, `ask-when-uncertain` (one batched prompt = one question).
|
|
74
|
+
- Threshold to surface at all: a **real, nameable** improvement with concrete benefit. Cosmetic nitpicks with no trade-off → drop silently. The live-security carve-out is the only case that interrupts or overrides autonomy.
|
|
75
|
+
|
|
76
|
+
## When it fires
|
|
77
|
+
|
|
78
|
+
While implementing/modifying code you pass an issue outside the literal task. Also on explicit "clean this up / modernize / dedupe".
|
|
79
|
+
|
|
80
|
+
## When NOT to fire
|
|
81
|
+
|
|
82
|
+
- No issue spotted. Prose/docs-only. User fenced the scope ("just this one line").
|
|
83
|
+
- The issue is the task itself — then it's just the task (no ladder needed).
|
|
84
|
+
|
|
85
|
+
## See also
|
|
86
|
+
|
|
87
|
+
- [`minimal-safe-diff`](minimal-safe-diff.md) — the carve-out above is bounded by it; everything outside the five conditions stays note+ask.
|
|
88
|
+
- [`broken-access-control`](broken-access-control.md) — the security category + the live-exposure carve-out.
|
|
89
|
+
- [`prefer-enums-over-literals`](prefer-enums-over-literals.md) — an instance of this ladder (enum literals).
|
|
90
|
+
- [`source-discovery-gate`](source-discovery-gate.md) — establishing the verified project version before modernizing.
|
|
91
|
+
- [`scope-control`](scope-control.md), [`commit-policy`](commit-policy.md) — PR/commit creation stays permission-gated.
|
|
92
|
+
- [`improve-before-implement`](improve-before-implement.md) — the pre-work challenge (before); this is the during/after remediation.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: "auto"
|
|
3
|
+
tier: "2a"
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
description: "Endpoint/query returning user or tenant data — authenticated ≠ authorized; enforce a server-derived ownership/tenant/role check + the three negative tests (401/non-owner/cross-tenant)"
|
|
6
|
+
triggers:
|
|
7
|
+
- intent: "returning user or tenant data"
|
|
8
|
+
- intent: "adding an endpoint that reads a record by id"
|
|
9
|
+
- keyword: "endpoint"
|
|
10
|
+
- keyword: "route"
|
|
11
|
+
- keyword: "authorization"
|
|
12
|
+
- keyword: "tenant"
|
|
13
|
+
- keyword: "IDOR"
|
|
14
|
+
- keyword: "session"
|
|
15
|
+
- keyword: "login"
|
|
16
|
+
- keyword: "controller"
|
|
17
|
+
- keyword: "findById"
|
|
18
|
+
routes_to:
|
|
19
|
+
- "skill:authz-review"
|
|
20
|
+
- "skill:threat-modeling"
|
|
21
|
+
- "skill:multi-tenancy"
|
|
22
|
+
workspaces: [engineering]
|
|
23
|
+
packs: [engineering-base]
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
# Broken Access Control
|
|
27
|
+
|
|
28
|
+
The most common — and most damaging — failure in real systems and AI-written code: log in as one user, see another user's data. **Authenticated ≠ authorized.** The login check passes so the endpoint *feels* protected; the per-object ownership/tenant check is a separate line devs and AI omit — especially when the object id comes from the request. OWASP Web #1 (A01:2021) and API #1 (BOLA/IDOR), trivially scriptable, and a recurring real-world breach class — e.g. First American Financial (885M documents exposed via sequential ids with no ownership check).
|
|
29
|
+
|
|
30
|
+
## The Iron Law
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
AUTHENTICATED IS NOT AUTHORIZED. EVERY REQUEST-SUPPLIED ID/FILTER GETS A
|
|
34
|
+
SERVER-DERIVED OWNERSHIP/TENANT CHECK BEFORE ANY DATA IS RETURNED.
|
|
35
|
+
NO DATA-RETURNING ENDPOINT IS DONE WITHOUT THREE NEGATIVE TESTS:
|
|
36
|
+
UNAUTHENTICATED → 401 · NOT-OWNER → 403/404 · CROSS-TENANT → 403/404 (404 HIDES EXISTENCE).
|
|
37
|
+
ROLE DECIDES WHICH FIELDS — THE SERVER STRIPS THEM. THE FRONTEND HIDING A FIELD IS NOT PROTECTION.
|
|
38
|
+
A LIVE CROSS-USER EXPOSURE IS A NOTIFIABLE BREACH — NEVER SILENTLY PATCH IT.
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Non-optional controls (every data-returning surface)
|
|
42
|
+
|
|
43
|
+
- **Server-derived principal.** Ownership/tenant derived from the session/token, **never** from a request header/param/body the caller controls. A matching id in the request is not authorization.
|
|
44
|
+
- **Ownership/tenant check on every request id** before returning data. `findById(params.id)` with no `where owner/tenant = currentPrincipal` is the canonical bug.
|
|
45
|
+
- **Tenant-scoped by construction.** Every query on a tenant table carries the tenant predicate; prefer a base scope that injects it so a forgotten clause can't leak. (DSGVO: Mandantentrennung / Trennungskontrolle is a required TOM — a missing `tenant_id` filter is a compliance failure, not just a bug.)
|
|
46
|
+
- **Response minimization.** Return only entitled fields — no `SELECT *` / full-object serialization leaking PII "because the model has it" (Art. 25(2)).
|
|
47
|
+
- **Property-level authz (BOPLA / mass assignment).** Reject `role` / `user_id` / `tenant_id` / `is_admin` from the request body; explicit field allow-list, never whole-body binding.
|
|
48
|
+
- **Role/field-level output filtering (vertical BOPLA).** *Which* fields a principal receives depends on role + business rules — a driver role must not receive `price`; an office role must not receive the boss's `offer`. Serialize via a **role-scoped output DTO**, never the raw model / `to_json()`; sensitive fields (`price`/`cost`/`margin`/`salary`/`discount`/`offer`/internal notes) default-deny per role.
|
|
49
|
+
- **No guessable public ids** on sensitive resources — UUID/ULID, not sequential integers (turns one bug into full-DB enumeration).
|
|
50
|
+
|
|
51
|
+
## The three negative tests — the completion gate
|
|
52
|
+
|
|
53
|
+
A protected endpoint is **not complete** until these exist and pass (happy-path 200 alone is the tautology this rule stops):
|
|
54
|
+
|
|
55
|
+
1. **unauthenticated → 401** (no token).
|
|
56
|
+
2. **authenticated but not the owner → 403/404** (user A requests user B's object with A's token).
|
|
57
|
+
3. **cross-tenant → 403/404** (a principal in tenant A requests tenant B's resource; prefer 404 on sensitive resources — a hard 403 confirms the id exists in another tenant).
|
|
58
|
+
|
|
59
|
+
Small + task-aligned gap in code you touched → add the check **and** its negative test in the same commit (auto-fix boundary in `active-remediation`). Bigger → surface it.
|
|
60
|
+
|
|
61
|
+
## Role-based field-level access — both directions (vertical BOPLA + BFLA)
|
|
62
|
+
|
|
63
|
+
Object-ownership (above) is *horizontal* (may this principal touch this record). This is *vertical*: which **fields** and which **functions** a role may reach — the maintainer's case (driver ≠ price, office worker ≠ boss's offer). Depends on role + business rules, and **the server is the only boundary** — the frontend hiding a field does not protect it: the raw JSON on the wire is readable via `curl`/DevTools/a proxy (3Fun leak: a privacy toggle filtered only in the app; the server returned every user's location to a direct query).
|
|
64
|
+
|
|
65
|
+
- **Read side (CWE-213 / Excessive Data Exposure).** Build the response from a **role-scoped output DTO** — never serialize the ORM model directly. Sensitive fields default-deny per role. A client `?fields=` selection is ergonomics, not authorization — intersect it server-side with the role's read-allowlist.
|
|
66
|
+
- **Write side (CWE-915).** Bind input through a **role-scoped write-allowlist** — never the raw body. Read-allowed ≠ write-allowed: a role may *see* `status` but not *set* `status:"approved"`; two independent sets.
|
|
67
|
+
- **Function level (BFLA, OWASP API #5).** A role must not reach a function/verb reserved for a higher role. Gate **every mutating verb** (POST/PUT/PATCH/DELETE), deny-by-default — not just the GET you were asked about. The admin button being hidden is not a control.
|
|
68
|
+
- **Nested / GraphQL.** Field-level checks propagate to nested selections; a low-role token selecting a restricted field gets null/error, not data.
|
|
69
|
+
- **Negative tests, per (role × sensitive field), both directions:** lower-role token → the field is **absent from the raw response body** (assert the body, not the UI); lower-role setting it on input → rejected/ignored, **verified by re-reading the persisted record**; every privileged verb → 403 for lower roles (403/404 on sensitive object reads).
|
|
70
|
+
|
|
71
|
+
## Defense-in-depth (so one miss can't leak)
|
|
72
|
+
|
|
73
|
+
Stack ≥2 independent layers on sensitive data — query-level ownership scoping, a centralized default-deny policy layer (a route with no policy is denied, not silently open), and DB row-level security as the backstop for a forgotten `WHERE tenant_id`. The RLS / policy-layer configuration, the per-role authz matrix, and the audit greps live once in [`authz-review`](../skills/authz-review/SKILL.md).
|
|
74
|
+
|
|
75
|
+
## GDPR / DSGVO — data protection by design
|
|
76
|
+
|
|
77
|
+
A cross-user leak violates **Art. 5(1)(f)** (integrity & confidentiality — a principle → higher fine tier), **Art. 25** (by design/default: default-deny + least privilege + response minimization), and **Art. 32** — which also **mandates a process for regularly testing effectiveness** of these controls (untested authz is a direct Art. 32 gap; hence the three negative tests are non-optional). A discovered live exposure is a **notifiable breach** (Art. 33, 72 h from discovery) — surface as "notify + remediate", never a silent patch. Data-protection context, not legal advice → `privacy-review`, `domain-safety-pii`.
|
|
78
|
+
|
|
79
|
+
## Backstop greps (authoring-time)
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
# Record fetched by request id with no owner/tenant predicate nearby (high-noise — a hit means read the line, not auto-fix)
|
|
83
|
+
rg -n '(findById|find|findOne|get)\(\s*(req\.|request\.|params\.|\$request|\$id)'
|
|
84
|
+
# Client-supplied tenant/user hint used as the scope (should come from the session)
|
|
85
|
+
rg -n '(tenant|tenantId|user_id|userId)\s*=\s*(req|request|params|headers|query)\.'
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
The full authoring-time grep set (mass-assignment, raw-serialization, secrets) lives once in [`ai-code-blindspots`](../skills/ai-code-blindspots/SKILL.md).
|
|
89
|
+
|
|
90
|
+
A hit means read that line — is the ownership/tenant check present? Some are safe (already scoped); none should ship unchecked.
|
|
91
|
+
|
|
92
|
+
## When it fires
|
|
93
|
+
|
|
94
|
+
Writing/modifying any endpoint, route, query, or serializer returning user- or tenant-owned data, or any auth/session/login/tenant path.
|
|
95
|
+
|
|
96
|
+
## When NOT to fire
|
|
97
|
+
|
|
98
|
+
- Public, non-user-specific data with no principal concept (public docs page, health check with no data).
|
|
99
|
+
- Prose/docs/config-only edits.
|
|
100
|
+
|
|
101
|
+
## See also
|
|
102
|
+
|
|
103
|
+
- [`authz-review`](../skills/authz-review/SKILL.md) — the 6-stage per-entrypoint chain, defense-in-depth, authz matrix, negative-test contract.
|
|
104
|
+
- [`security-sensitive-stop`](security-sensitive-stop.md) — threat-model BEFORE editing an auth/tenant path (fires first).
|
|
105
|
+
- [`active-remediation`](active-remediation.md) — the fix-now/ask/follow-up ladder + the live-exposure safety carve-out.
|
|
106
|
+
- [`threat-modeling`](../skills/threat-modeling/SKILL.md), [`multi-tenancy`](../skills/multi-tenancy/SKILL.md), [`ai-code-blindspots`](../skills/ai-code-blindspots/SKILL.md), [`privacy-review`](../skills/privacy-review/SKILL.md).
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: "auto"
|
|
3
|
+
tier: "2b"
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
description: "Multi-step or continuation replies carry a red thread — state the goal once, tie each turn back to it, name what changed since last turn, close the loop with one end-summary"
|
|
6
|
+
triggers:
|
|
7
|
+
- intent: "producing a multi-step or continuation reply"
|
|
8
|
+
- intent: "reporting progress on ongoing work"
|
|
9
|
+
workspaces: [agent-config-maintainer, construction, engineering, finance, founder, gtm, legal-review-prep, ops, product, small-business]
|
|
10
|
+
packs: [engineering-base]
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Communication Through-Line
|
|
14
|
+
|
|
15
|
+
The user follows the work through your replies. A multi-step task whose replies jump between sub-topics with no visible thread forces the user to re-derive where things stand every turn. Give the work a **red thread**: a followable narrative from goal to result. Session-spanning coherence — distinct from single-reply brevity (`direct-answers`) and option formatting (`user-interaction`), which it never overrides.
|
|
16
|
+
|
|
17
|
+
## The Iron Law
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
STATE THE GOAL ONCE. TIE EACH TURN BACK TO IT. NAME WHAT CHANGED SINCE THE LAST TURN.
|
|
21
|
+
CLOSE THE LOOP WITH ONE END-SUMMARY. NEVER MAKE THE USER RE-DERIVE WHERE THINGS STAND.
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Checkable behaviors
|
|
25
|
+
|
|
26
|
+
- **Anchor once.** At the start of a multi-step task, state the goal/plan in one line (not re-stated every turn).
|
|
27
|
+
- **Each turn locates itself.** A mid-task reply says, in a few words, where it sits in the plan ("step 3/5", "now the downstream wiring") — so the user never scrolls up to orient.
|
|
28
|
+
- **Name the delta.** On a continuation, say what changed since the last turn (what landed, what's next) rather than restating everything.
|
|
29
|
+
- **Close the loop.** A work reply ends with ONE end-summary mapping back to the stated goal — reached or not, what remains. (Same single end-summary `direct-answers` requires; do not add a second.)
|
|
30
|
+
- **Signal pivots.** If the work changes direction (new sub-task, interrupt, blocker), say so explicitly — a silent topic switch breaks the thread.
|
|
31
|
+
|
|
32
|
+
## When NOT to over-apply
|
|
33
|
+
|
|
34
|
+
- A one-shot answer or trivial reply needs no plan-anchor or end-summary (`direct-answers` brevity wins).
|
|
35
|
+
- Don't narrate for its own sake — the thread is orientation, not play-by-play (respect `personal.play_by_play`).
|
|
36
|
+
- Never let the through-line inflate a reply past what the task needs; brevity and the one-recommendation rule win on conflict.
|
|
37
|
+
|
|
38
|
+
## See also
|
|
39
|
+
|
|
40
|
+
- [`direct-answers`](direct-answers.md) — brevity + the single end-summary this closes the loop with.
|
|
41
|
+
- [`user-interaction`](user-interaction.md) — the one-recommendation format; through-line never adds a competing summary.
|
|
42
|
+
- [`language-and-tone`](language-and-tone.md) — the thread is in the user's language.
|
|
@@ -45,6 +45,14 @@ ceiling on what the package may ever become.
|
|
|
45
45
|
`telegraph-speak`, thin-projector trimming) that rejects a change on
|
|
46
46
|
cost grounds alone.
|
|
47
47
|
- An ADR whose decision is being cited as a blocker for the current change.
|
|
48
|
+
- A **hard structural cap** (kernel size, per-domain persona cap, rich-skill
|
|
49
|
+
ratio). A change that genuinely *qualifies* to cross the cap — e.g. a new
|
|
50
|
+
rule that truly meets the kernel-membership inclusion criteria — triggers a
|
|
51
|
+
**cap-raise proposal + maintainer/council approval**, never a silent
|
|
52
|
+
downgrade of the rule to fit the old number (e.g. demoting a must-always-fire
|
|
53
|
+
rule to `auto` just because the kernel says 9). Fitting the cap is not a
|
|
54
|
+
reason to weaken a qualifying rule; but a rule that does **not** meet the
|
|
55
|
+
criteria stays out — the cap is not the reason, the criteria are.
|
|
48
56
|
|
|
49
57
|
## What to do when it fires
|
|
50
58
|
|
|
@@ -98,4 +98,21 @@ After the incident, open a **follow-up PR** for any scope that was
|
|
|
98
98
|
intentionally deferred and reference the break-glass commit in its
|
|
99
99
|
description.
|
|
100
100
|
|
|
101
|
-
|
|
101
|
+
## Bounded remediation carve-out
|
|
102
|
+
|
|
103
|
+
The default stands: no drive-by edits, no opportunistic refactors. The one
|
|
104
|
+
bounded exception — a **small, task-aligned security/correctness fix in code
|
|
105
|
+
the current task already touches** — is governed by
|
|
106
|
+
[`active-remediation`](active-remediation.md). Permitted inline **only** when
|
|
107
|
+
ALL hold: same request path / module, ≤ ~10 changed lines in one production file (plus its test file),
|
|
108
|
+
no public-API / response-shape change, no dependency bump or migration, and
|
|
109
|
+
its verification (e.g. the negative test) ships in the same commit. Anything
|
|
110
|
+
outside those five conditions is **not** this carve-out — it is note + ask per
|
|
111
|
+
`active-remediation`. This never licenses reformatting, renames, dependency
|
|
112
|
+
bumps, or version upgrades (a syntax-idiom modernization is allowed only under
|
|
113
|
+
`active-remediation`'s version-gated, behavior-preserving clause; a
|
|
114
|
+
dependency/version bump stays ask-only). The sole case that may interrupt is a
|
|
115
|
+
**live cross-user/tenant data exposure** ([`broken-access-control`](broken-access-control.md)) —
|
|
116
|
+
fix-now-if-small, else stop and surface; never defer it silently.
|
|
117
|
+
|
|
118
|
+
See also: `scope-control` · `downstream-changes` · `think-before-action` · `preservation-guard` · `verify-before-complete` · [`active-remediation`](active-remediation.md) · [`broken-access-control`](broken-access-control.md).
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: "auto"
|
|
3
|
+
tier: "2b"
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
description: "Modeling a field/property with multiple non-boolean states — prefer an enum over bare string/numeric literals; found old-style literals where an enum fits → note, finish the task, ask after"
|
|
6
|
+
triggers:
|
|
7
|
+
- intent: "modeling a field with multiple states"
|
|
8
|
+
- intent: "adding a status or type field"
|
|
9
|
+
- keyword: "enum"
|
|
10
|
+
- keyword: "status"
|
|
11
|
+
- keyword: "kind"
|
|
12
|
+
- keyword: "category"
|
|
13
|
+
- keyword: "migration"
|
|
14
|
+
workspaces: [engineering]
|
|
15
|
+
packs: [engineering-base]
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# Prefer Enums Over Literal Values
|
|
19
|
+
|
|
20
|
+
When a field/property holds **two or more non-boolean states** — strings (`'active'`, `'pending'`, `'archived'`) or meaningful numeric codes (priority `1`/`2`/`3`, tier levels) — model it as an **enum**, not a bare string/int. An enum names the value in code (readable), makes it greppable + safe to rename, gives exhaustiveness/typo safety, and makes filtering + editing relations far easier than raw literals scattered across the codebase.
|
|
21
|
+
|
|
22
|
+
## The Iron Law
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
A FIELD WITH MULTIPLE NON-BOOLEAN STATES IS AN ENUM, NOT A BARE STRING OR MAGIC NUMBER.
|
|
26
|
+
NAME THE VALUE IN CODE — NEVER SCATTER RAW LITERALS ('active', 2, 'PENDING') ACROSS THE CODEBASE.
|
|
27
|
+
FOUND OLD-STYLE LITERALS WHERE AN ENUM FITS? NOTE IT, FINISH THE TASK, THEN ASK — NEVER REFACTOR MID-FLOW.
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Prefer an enum when
|
|
31
|
+
|
|
32
|
+
- A multi-state **string** field — `status`, `type`, `role`, `kind`, `category`, `state` — with 2+ distinct values.
|
|
33
|
+
- A **numeric code that is a label, not a quantity** — priority `1/2/3`, severity levels, tiers.
|
|
34
|
+
- Any **closed set of values the code branches on** (`match` / `switch` / `if ===`).
|
|
35
|
+
|
|
36
|
+
## Do NOT force an enum when
|
|
37
|
+
|
|
38
|
+
- A boolean (`true`/`false`) — a flag, not an enum.
|
|
39
|
+
- Open/unbounded free text — name, description, URL, comment.
|
|
40
|
+
- A genuine numeric **quantity** used in arithmetic — price, count, age, bytes.
|
|
41
|
+
- A set owned entirely by a volatile external system — unless you map it to your own enum at the boundary.
|
|
42
|
+
|
|
43
|
+
## How (framework-neutral)
|
|
44
|
+
|
|
45
|
+
- Use the language's native construct: backed enum (PHP `enum Status: string`), string-literal union or `enum` (TypeScript), `enum.Enum` (Python), an enum/`CHECK`-constrained column or lookup table + FK (database).
|
|
46
|
+
- Persist the enum's backing value; reference the **named case** in code, never the raw literal.
|
|
47
|
+
|
|
48
|
+
## Found old-style literals where an enum fits — defer, do not disrupt
|
|
49
|
+
|
|
50
|
+
Apply exactly this order so the current task's flow is never interrupted:
|
|
51
|
+
|
|
52
|
+
1. **While doing the actual task**, if you pass code using raw string/numeric literals for a multi-state field where an enum fits, do **NOT** refactor inline (a drive-by edit — see `minimal-safe-diff`) and do **NOT** stop to ask mid-flow.
|
|
53
|
+
2. **Note the site** — file:line + the literal set — in your working notes.
|
|
54
|
+
3. **After the actual task is delivered**, surface the noted candidates as **one** numbered-options prompt (per `user-interaction`): list each enum-candidate site, ask whether to replace — all / selected / none.
|
|
55
|
+
4. **Only on an explicit yes** do you refactor, as a **separate change** with its own scope (`downstream-changes` applies — update every caller, migration, test, serializer).
|
|
56
|
+
|
|
57
|
+
If the task itself is *adding* the field, apply the enum from the start — no deferral; the defer-and-ask flow is only for pre-existing literals you encounter.
|
|
58
|
+
|
|
59
|
+
## See also
|
|
60
|
+
|
|
61
|
+
- [`improve-before-implement`](improve-before-implement.md) — the Strategy sniff test when a second branch on the same enum/string discriminator signals the enum should become a Strategy (`docs/guidelines/php/patterns/strategy.md`).
|
|
62
|
+
- [`minimal-safe-diff`](minimal-safe-diff.md) — why you don't drive-by-refactor the literals you find.
|
|
63
|
+
- [`scope-control`](scope-control.md) — replacing an existing pattern needs the user's yes first.
|
|
64
|
+
- [`active-remediation`](active-remediation.md) — the general fix-now / note-and-ask / follow-up-PR ladder; the enum defer-and-ask above is one instance of it.
|
|
65
|
+
- [`senior-engineering-discipline`](senior-engineering-discipline.md) — the "generalize, don't overfit" anchor this extends.
|