@event4u/agent-config 15.0.0 → 16.1.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/.augment-plugin/marketplace.json +3 -3
- package/.augment-plugin/plugin.json +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +301 -347
- package/CONTRIBUTING.md +9 -0
- package/README.md +2 -2
- package/dist/agent-src/commands/analyze/inbox.md +26 -0
- package/dist/agent-src/commands/analyze/roadmap-repos.md +27 -0
- package/dist/agent-src/commands/challenge-me/closure.md +178 -0
- package/dist/agent-src/commands/challenge-me.md +9 -2
- package/dist/agent-src/commands/council/default.md +25 -5
- package/dist/agent-src/commands/feature/plan.md +28 -1
- package/dist/agent-src/commands/feature/roadmap.md +28 -1
- package/dist/agent-src/commands/implement-ticket.md +27 -0
- package/dist/agent-src/commands/jira-ticket.md +27 -0
- package/dist/agent-src/commands/pr/create.md +29 -0
- package/dist/agent-src/commands/pr/merge.md +60 -9
- package/dist/agent-src/commands/roadmap/ai-council.md +7 -1
- package/dist/agent-src/commands/roadmap/create.md +77 -29
- package/dist/agent-src/commands/roadmap/materialize.md +27 -0
- package/dist/agent-src/commands/roadmap/process-full.md +123 -18
- package/dist/agent-src/commands/team.md +22 -0
- package/dist/agent-src/contexts/authority/scope-growth-ownership.md +80 -0
- package/dist/agent-src/contexts/communication/rules-auto/user-interaction-mechanics.md +97 -0
- package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +44 -3
- package/dist/agent-src/contexts/execution/autonomy-mechanics.md +15 -15
- package/dist/agent-src/contexts/execution/decision-closure-execution.md +93 -0
- package/dist/agent-src/contexts/execution/fix-loop-ladder.md +108 -0
- package/dist/agent-src/contexts/execution/plan-confidence-gate.md +4 -2
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +75 -6
- package/dist/agent-src/guidelines/agent-infra/active-remediation-mechanics.md +57 -0
- package/dist/agent-src/guidelines/agent-infra/evaluator-independence-mechanics.md +102 -0
- package/dist/agent-src/guidelines/design-fidelity-routing.md +29 -0
- package/dist/agent-src/rules/autonomous-execution.md +15 -8
- package/dist/agent-src/rules/delegation-policy.md +23 -45
- package/dist/agent-src/rules/design-fidelity.md +32 -37
- package/dist/agent-src/rules/evaluator-independence.md +43 -49
- package/dist/agent-src/rules/test-first.md +41 -0
- package/dist/agent-src/rules/user-interaction.md +31 -30
- package/dist/agent-src/skills/accessibility-auditor/data/manifest.json +3 -3
- package/dist/agent-src/skills/ai-council/SKILL.md +11 -3
- package/dist/agent-src/skills/api-design/data/manifest.json +3 -3
- package/dist/agent-src/skills/database/data/manifest.json +4 -4
- package/dist/agent-src/skills/database/data/query-tuning.csv +3 -3
- package/dist/agent-src/skills/design-review/SKILL.md +50 -0
- package/dist/agent-src/skills/error-handling-patterns/SKILL.md +9 -0
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +14 -4
- package/dist/agent-src/skills/experiment-loop/SKILL.md +31 -1
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +1 -1
- package/dist/agent-src/skills/storybook-workshop/SKILL.md +42 -3
- package/dist/agent-src/skills/threat-modeling/SKILL.md +9 -4
- package/dist/agent-src/skills/threat-modeling/data/manifest.json +4 -4
- package/dist/agent-src/skills/verify-repair-loop/SKILL.md +37 -3
- package/dist/agent-src/templates/agent-settings.md +1 -1
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/roadmaps.md +188 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +62 -2
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/test.ts +1 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +1 -0
- package/dist/cli-delegate/check_update_banner.js +40 -2
- package/dist/cli-delegate/chunk-4E2W63DA.js +335 -0
- package/dist/cli-delegate/chunk-5R7HOLAF.js +99 -0
- package/dist/cli-delegate/{chunk-IVBPRCQO.js → chunk-6KFEC3G7.js} +1 -1
- package/dist/cli-delegate/{chunk-2TAQ2K4V.js → chunk-6KM6ORRY.js} +55 -386
- package/dist/cli-delegate/{chunk-2XY7ILBT.js → chunk-FC75PGJE.js} +42 -2
- package/dist/cli-delegate/{chunk-GYC3VRYN.js → chunk-FXYUYU4N.js} +57 -13
- package/dist/cli-delegate/{chunk-55ACLDUE.js → chunk-GJCBB2UG.js} +168 -10
- package/dist/cli-delegate/{chunk-AK6HODNQ.js → chunk-HDVVGPQW.js} +873 -539
- package/dist/cli-delegate/chunk-NUHLI2RX.js +80 -0
- package/dist/cli-delegate/{chunk-HZ52BRGG.js → chunk-P6ZHP5W2.js} +15 -90
- package/dist/cli-delegate/{chunk-TYSY33MD.js → chunk-QJWAUMJW.js} +12 -2
- package/dist/cli-delegate/{chunk-57PN4GYJ.js → chunk-RGNIWTEA.js} +1 -1
- package/dist/cli-delegate/chunk-ROYYTEZU.js +39 -0
- package/dist/cli-delegate/{chunk-2KKXJW25.js → chunk-S3VFXMTM.js} +1 -1
- package/dist/cli-delegate/{chunk-3FKR64R5.js → chunk-UNCRJBT3.js} +31 -7
- package/dist/cli-delegate/{chunk-2DK2VJWG.js → chunk-WGXTVKCQ.js} +20 -6
- package/dist/cli-delegate/chunk-YDPILCOL.js +152 -0
- package/dist/cli-delegate/cmd_analyze_session.js +1 -1
- package/dist/cli-delegate/cmd_brand_status.js +1 -1
- package/dist/cli-delegate/cmd_conformance.js +918 -325
- package/dist/cli-delegate/cmd_doctor.js +7 -5
- package/dist/cli-delegate/cmd_explain.js +5 -3
- package/dist/cli-delegate/cmd_export.js +9 -7
- package/dist/cli-delegate/cmd_fleet.js +4 -2
- package/dist/cli-delegate/cmd_handoff.js +6 -6
- package/dist/cli-delegate/cmd_mcp_available.js +1 -1
- package/dist/cli-delegate/cmd_migrate.js +2 -2
- package/dist/cli-delegate/cmd_packs_active.js +3 -2
- package/dist/cli-delegate/cmd_preflight.js +4 -2
- package/dist/cli-delegate/cmd_prune.js +10 -8
- package/dist/cli-delegate/cmd_route_audit.js +2 -2
- package/dist/cli-delegate/cmd_route_explain.js +1 -1
- package/dist/cli-delegate/cmd_session_recycle.js +4 -4
- package/dist/cli-delegate/cmd_settings_get.js +28 -2
- package/dist/cli-delegate/cmd_settings_migrate.js +9 -7
- package/dist/cli-delegate/cmd_settings_set.js +14 -1
- package/dist/cli-delegate/cmd_sync.js +10 -8
- package/dist/cli-delegate/cmd_uninstall.js +16 -13
- package/dist/cli-delegate/cmd_update.js +1 -1
- package/dist/cli-delegate/cmd_upgrade.js +1 -1
- package/dist/cli-delegate/cmd_validate.js +12 -10
- package/dist/cli-delegate/cmd_versions.js +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +87 -40
- 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 +10 -8
- package/dist/discovery/trust-report.md +3 -3
- package/dist/discovery/workspaces.json +8 -6
- package/dist/hooks/dispatch.js +2601 -1073
- package/dist/install/claudeRuleRewrite.js +14 -3
- package/dist/install/conflict.js +60 -10
- package/dist/install/conflictTracker.js +218 -0
- package/dist/install/fsPrimitives.js +54 -0
- package/dist/install/install.mjs +2008 -1481
- package/dist/install/manifestFiles.js +259 -0
- package/dist/install/preflight.js +14 -2
- package/dist/install/preserve.js +157 -0
- package/dist/install/recordedOwnership.js +132 -0
- package/dist/install/txlog.js +11 -2
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +1612 -667
- package/dist/router.json +1 -1
- package/dist/scripts/_lib/agent_settings.js +3 -2
- package/dist/scripts/_lib/fs_atomic.js +167 -0
- package/dist/scripts/_lib/installed_lock.js +1 -1
- package/dist/scripts/_lib/installed_tools.js +460 -0
- package/dist/scripts/_lib/lean_projection_mode.js +3 -2
- package/dist/scripts/_lib/settings_renamed_keys.js +78 -0
- package/dist/server/io/yamlIO.js +50 -0
- package/dist/server/routes/install.js +8 -0
- package/dist/server/routes/wizard.js +9 -3
- package/dist/server/schemas/settings.js +17 -5
- package/dist/shared/missionExecution.js +97 -0
- package/dist/ui/assets/{index-D0jaCRPM.js → index-DH1xc62v.js} +17 -17
- package/dist/ui/index.html +1 -1
- package/docs/MIGRATION.md +103 -0
- package/docs/contracts/settings-classes.md +26 -7
- package/docs/guidelines/agent-infra/active-remediation-mechanics.md +57 -0
- package/docs/guidelines/agent-infra/evaluator-independence-mechanics.md +102 -0
- package/docs/guidelines/design-fidelity-routing.md +29 -0
- package/package.json +1 -1
- package/src/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +62 -2
- package/src/agent-src/templates/scripts/work_engine/directives/backend/test.ts +1 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +1 -0
- package/src/config/agent-settings.template.yml +139 -27
- package/src/config/auto-rule-budget.json +16 -0
- package/src/config/ci-local-parity.yml +18 -5
- package/src/config/continuity-surface.json +28 -0
- package/src/config/gate-coverage.yml +146 -13
- package/src/config/gate-violation-baselines.json +6 -6
- package/src/config/hook-token-budget.json +2 -0
- package/src/config/host-injection-effect.json +1 -1
- package/src/config/loop-surfaces.yaml +215 -0
- package/src/config/platform-anchor.json +3 -2
- package/src/config/preamble-payload-budget.json +12 -7
- package/src/config/preamble-payload-exceptions.json +28 -0
- package/src/config/release-gate-locality.yml +11 -0
- package/src/config/routing-coverage-seed.json +18 -4
- package/src/config/rule-enforcement-baseline.json +0 -1
- package/src/install/claudeRuleRewrite.ts +16 -2
- package/src/install/conflict.ts +65 -9
- package/src/install/conflictTracker.ts +299 -0
- package/src/install/fsPrimitives.ts +54 -0
- package/src/install/manifestFiles.ts +312 -0
- package/src/install/preflight.ts +16 -2
- package/src/install/preserve.ts +205 -0
- package/src/install/recordedOwnership.ts +149 -0
- package/src/install/txlog.ts +11 -2
- package/src/install/types.ts +19 -4
- package/src/scripts/_cli/cmd_conformance.ts +88 -15
- package/src/scripts/_cli/cmd_doctor.ts +4 -3
- package/src/scripts/_cli/cmd_route_explain.ts +9 -2
- package/src/scripts/_cli/cmd_settings_get.ts +44 -0
- package/src/scripts/_cli/doctor_execution.ts +90 -0
- package/src/scripts/_dispatch.bash +3 -1
- package/src/scripts/_lib/activation_payload.ts +247 -0
- package/src/scripts/_lib/agent_settings.ts +4 -2
- package/src/scripts/_lib/authority_path.ts +102 -0
- package/src/scripts/_lib/base_ref_payload.ts +315 -0
- package/src/scripts/_lib/cascade_base.ts +94 -0
- package/src/scripts/_lib/changelog_eras.ts +7 -2
- package/src/scripts/_lib/continuation_ladder.ts +149 -2
- package/src/scripts/_lib/council_transport.ts +129 -0
- package/src/scripts/_lib/delivery_ready.ts +112 -0
- package/src/scripts/_lib/dropped_decision.ts +142 -0
- package/src/scripts/_lib/forge_protection.ts +267 -0
- package/src/scripts/_lib/hook_platform_keys.ts +27 -0
- package/src/scripts/_lib/installed_lock.ts +1 -1
- package/src/scripts/_lib/json_python_parity.ts +127 -0
- package/src/scripts/_lib/lean_projection_mode.ts +14 -3
- package/src/scripts/_lib/loop_surfaces.ts +382 -0
- package/src/scripts/_lib/measured_payload_ceiling.ts +424 -0
- package/src/scripts/_lib/mission_record.ts +190 -0
- package/src/scripts/_lib/obligation_frequency.ts +217 -0
- package/src/scripts/_lib/obligations.ts +402 -0
- package/src/scripts/_lib/orchestration_record.ts +11 -20
- package/src/scripts/_lib/payload_catalogue_completeness.ts +211 -0
- package/src/scripts/_lib/release_findings_ingest.ts +324 -0
- package/src/scripts/_lib/release_highlights.ts +199 -10
- package/src/scripts/_lib/release_holds.ts +493 -0
- package/src/scripts/_lib/release_migration_gate.ts +184 -0
- package/src/scripts/_lib/release_tag_dispatch.ts +63 -0
- package/src/scripts/_lib/review_baseline.ts +254 -0
- package/src/scripts/_lib/review_skipped_record.ts +61 -1
- package/src/scripts/_lib/rides_along.ts +102 -0
- package/src/scripts/_lib/settings_renamed_keys.ts +82 -0
- package/src/scripts/_lib/standing_bound_ratchet.ts +216 -103
- package/src/scripts/_lib/test_delta.ts +166 -0
- package/src/scripts/_lib/test_provenance.ts +171 -0
- package/src/scripts/_lib/turn_end_refusals.ts +51 -4
- package/src/scripts/_lib/typed_op_grant.ts +246 -0
- package/src/scripts/_lib/typed_op_watch.ts +185 -0
- package/src/scripts/ai_council/config.ts +8 -11
- package/src/scripts/ai_council/fallback_config.ts +5 -3
- package/src/scripts/ai_council/ownership_classes.ts +118 -0
- package/src/scripts/ask_block_census.ts +285 -15
- package/src/scripts/check_beta_review_markers.ts +35 -4
- package/src/scripts/check_enforcement_matrix.ts +624 -0
- package/src/scripts/check_finding_dispositions.ts +167 -16
- package/src/scripts/check_gate_reachability.ts +173 -10
- package/src/scripts/check_generator_sync.ts +954 -0
- package/src/scripts/check_held_object_arrivals.ts +381 -0
- package/src/scripts/check_preamble_payload_budget.ts +474 -124
- package/src/scripts/check_release_highlights.ts +33 -1
- package/src/scripts/check_release_holds.ts +567 -0
- package/src/scripts/check_release_published.ts +1 -1
- package/src/scripts/check_reply_consistency.ts +86 -17
- package/src/scripts/check_rule_projection_integrity.ts +22 -12
- package/src/scripts/check_test_delta.ts +294 -0
- package/src/scripts/check_test_weakening.ts +299 -0
- package/src/scripts/closure_scan.ts +333 -0
- package/src/scripts/compile_hook_manifest.ts +43 -3
- package/src/scripts/council_record_shape.ts +209 -0
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +127 -12
- package/src/scripts/hooks/block_kernel_rule_writes.ts +12 -2
- package/src/scripts/hooks/concern_registry.ts +6 -0
- package/src/scripts/hooks/design_pass_hook.ts +128 -3
- package/src/scripts/hooks/end_review_nudge_hook.ts +101 -21
- package/src/scripts/hooks/evidence_independence.ts +96 -0
- package/src/scripts/hooks/memory_recall_hook.ts +540 -0
- package/src/scripts/hooks/obligation_settle_hook.ts +182 -0
- package/src/scripts/hooks/review_baseline_hook.ts +130 -0
- package/src/scripts/hooks/rule_inject_hook.ts +49 -1
- package/src/scripts/hooks/run_continuation_hook.ts +17 -20
- package/src/scripts/hooks/turn_end_gate_hook.ts +232 -14
- package/src/scripts/hooks_doctor.ts +89 -1
- package/src/scripts/hooks_status.ts +19 -0
- package/src/scripts/install.ts +107 -207
- package/src/scripts/interruption_report.ts +8 -2
- package/src/scripts/janitor.ts +15 -1
- package/src/scripts/lint_decision_classes.ts +464 -0
- package/src/scripts/lint_hook_manifest.ts +11 -0
- package/src/scripts/lint_major_migration_sections.ts +450 -0
- package/src/scripts/lint_plan_risk_register.ts +47 -3
- package/src/scripts/lint_roadmap_blockers.ts +61 -0
- package/src/scripts/lint_roadmap_producers.ts +202 -0
- package/src/scripts/measure_rule_budget.ts +101 -5
- package/src/scripts/measure_turn_end_gate.ts +302 -5
- package/src/scripts/new_roadmap.ts +37 -0
- package/src/scripts/orchestration_record.ts +0 -5
- package/src/scripts/release.ts +66 -162
- package/src/scripts/release_drill.ts +460 -15
- package/src/scripts/release_env.ts +1 -1
- package/src/scripts/release_publication.ts +52 -1
- package/src/scripts/report_enforcement_drift.ts +566 -0
- package/src/scripts/report_held_object_arrivals.ts +456 -0
- package/src/scripts/report_host_injection_effect.ts +3 -11
- package/src/scripts/report_standing_payload_by_host.ts +26 -152
- package/src/scripts/schemas/agent-settings.schema.json +23 -0
- package/src/scripts/schemas/command.schema.json +4 -0
- package/src/scripts/scope_growth.ts +219 -0
- package/src/scripts/sync_agent_settings.ts +140 -18
- package/src/scripts/trigger_eval_grandfather.json +0 -1
- package/src/scripts/ui_conformance_probe.ts +622 -0
- package/src/server/io/yamlIO.ts +48 -0
- package/src/server/schemas/settings.ts +31 -7
- package/src/shared/missionExecution.ts +126 -0
- package/dist/cli-delegate/chunk-523HCFYO.js +0 -90
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* Every roadmap producer ends in closure — mechanically, not by convention.
|
|
4
|
+
*
|
|
5
|
+
* A command that produces a plan and hands it back with open decisions in it
|
|
6
|
+
* has moved those decisions into execution, where meeting one costs a run.
|
|
7
|
+
* The entrance list used to be hard-coded in three command bodies, so the
|
|
8
|
+
* other six producers were simply not in it and nothing said so.
|
|
9
|
+
*
|
|
10
|
+
* The declaration is now the command's own: `produces_roadmap: true` in the
|
|
11
|
+
* frontmatter. This gate reds a command that declares it and does not end in
|
|
12
|
+
* the closure pass, which is the half a hard-coded list could never check.
|
|
13
|
+
*
|
|
14
|
+
* What counts as ending in closure: the body references the closure pass by
|
|
15
|
+
* one of its two names — the `/challenge-me closure` sub-command, or the
|
|
16
|
+
* `closure_scan` detector it runs. Deliberately a reference check rather than
|
|
17
|
+
* a prose check: prose drifts, and a gate that guesses at intent from wording
|
|
18
|
+
* is the detector that gets weakened until it finds nothing.
|
|
19
|
+
*
|
|
20
|
+
* Exit codes: 0 clean · 1 violations · 2 internal error / bad argv.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import * as fs from 'node:fs';
|
|
24
|
+
import * as path from 'node:path';
|
|
25
|
+
import process from 'node:process';
|
|
26
|
+
import { fileURLToPath } from 'node:url';
|
|
27
|
+
|
|
28
|
+
import { assertScanned, DeadScopeError } from './_lib/scan_scope.js';
|
|
29
|
+
|
|
30
|
+
const _HERE = fileURLToPath(import.meta.url);
|
|
31
|
+
const _PROG = 'lint_roadmap_producers';
|
|
32
|
+
|
|
33
|
+
/** The frontmatter declaration a producer carries. */
|
|
34
|
+
export const DECLARATION_RE = /^produces_roadmap:\s*true\s*$/m;
|
|
35
|
+
|
|
36
|
+
/** Either name of the closure pass discharges the obligation. */
|
|
37
|
+
export const CLOSURE_REFS: readonly RegExp[] = [
|
|
38
|
+
/\/challenge-me\s+closure/,
|
|
39
|
+
/challenge-me\/closure/,
|
|
40
|
+
/\bclosure_scan\b/,
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
export interface Violation {
|
|
44
|
+
readonly file: string;
|
|
45
|
+
readonly reason: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function _frontmatter(text: string): string {
|
|
49
|
+
if (!text.startsWith('---')) return '';
|
|
50
|
+
const end = text.indexOf('\n---', 3);
|
|
51
|
+
return end < 0 ? '' : text.slice(0, end);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function declaresProducer(text: string): boolean {
|
|
55
|
+
return DECLARATION_RE.test(_frontmatter(text));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function endsInClosure(text: string): boolean {
|
|
59
|
+
return CLOSURE_REFS.some((re) => re.test(text));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function checkFile(rel: string, text: string): Violation[] {
|
|
63
|
+
if (!declaresProducer(text)) return [];
|
|
64
|
+
if (endsInClosure(text)) return [];
|
|
65
|
+
return [
|
|
66
|
+
{
|
|
67
|
+
file: rel,
|
|
68
|
+
reason:
|
|
69
|
+
'declares `produces_roadmap: true` and does not end in the closure pass — ' +
|
|
70
|
+
'a producer hands back an execution contract, not a plan with open decisions ' +
|
|
71
|
+
'in it. Reference `/challenge-me closure` (or the `closure_scan` detector) ' +
|
|
72
|
+
'as the command’s last step.',
|
|
73
|
+
},
|
|
74
|
+
];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function _walk(dir: string, out: string[]): void {
|
|
78
|
+
let entries: fs.Dirent[];
|
|
79
|
+
try {
|
|
80
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
81
|
+
} catch {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
for (const e of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
85
|
+
const full = path.join(dir, e.name);
|
|
86
|
+
if (e.isDirectory()) _walk(full, out);
|
|
87
|
+
else if (e.isFile() && e.name === 'command.md') out.push(full);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function listCommands(root: string): string[] {
|
|
92
|
+
const out: string[] = [];
|
|
93
|
+
_walk(root, out);
|
|
94
|
+
return out;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function _repoRoot(): string {
|
|
98
|
+
return path.resolve(path.dirname(_HERE), '..', '..');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function _usage(): string {
|
|
102
|
+
return (
|
|
103
|
+
`usage: ${_PROG} [-h] [--quiet] [--json] [--self-test]\n\n` +
|
|
104
|
+
`Every command declaring \`produces_roadmap: true\` ends in the closure pass.\n`
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function main(argv?: readonly string[]): number {
|
|
109
|
+
const args = argv ?? process.argv.slice(2);
|
|
110
|
+
let quiet = false;
|
|
111
|
+
let json = false;
|
|
112
|
+
let selfTest = false;
|
|
113
|
+
const unknown: string[] = [];
|
|
114
|
+
for (const a of args) {
|
|
115
|
+
if (a === '-h' || a === '--help') {
|
|
116
|
+
process.stdout.write(_usage());
|
|
117
|
+
return 0;
|
|
118
|
+
} else if (a === '--quiet') quiet = true;
|
|
119
|
+
else if (a === '--json') json = true;
|
|
120
|
+
else if (a === '--self-test') selfTest = true;
|
|
121
|
+
else unknown.push(a);
|
|
122
|
+
}
|
|
123
|
+
if (unknown.length) {
|
|
124
|
+
process.stderr.write(`${_usage()}${_PROG}: error: unrecognized arguments: ${unknown.join(' ')}\n`);
|
|
125
|
+
return 2;
|
|
126
|
+
}
|
|
127
|
+
if (selfTest) return _selfTest();
|
|
128
|
+
|
|
129
|
+
const repo = _repoRoot();
|
|
130
|
+
const root = path.join(repo, 'src', 'domains');
|
|
131
|
+
const files = listCommands(root);
|
|
132
|
+
const producers = files.filter((f) => declaresProducer(fs.readFileSync(f, 'utf-8')));
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
// The corpus is the DECLARED producers, not every command: a tree where
|
|
136
|
+
// nobody declares the key is a tree where the declaration was lost, and
|
|
137
|
+
// that is exactly the silent-disarm this assertion exists to catch.
|
|
138
|
+
assertScanned({
|
|
139
|
+
gate: _PROG,
|
|
140
|
+
scanned: producers.length,
|
|
141
|
+
units: 'roadmap producer(s)',
|
|
142
|
+
roots: ['src/domains'],
|
|
143
|
+
});
|
|
144
|
+
} catch (e) {
|
|
145
|
+
if (e instanceof DeadScopeError) {
|
|
146
|
+
process.stderr.write(`❌ ${e.message}\n`);
|
|
147
|
+
return 2;
|
|
148
|
+
}
|
|
149
|
+
throw e;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const violations: Violation[] = [];
|
|
153
|
+
for (const f of producers) {
|
|
154
|
+
violations.push(...checkFile(path.relative(repo, f), fs.readFileSync(f, 'utf-8')));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (json) {
|
|
158
|
+
process.stdout.write(JSON.stringify(violations, null, 2) + '\n');
|
|
159
|
+
return violations.length ? 1 : 0;
|
|
160
|
+
}
|
|
161
|
+
if (violations.length) {
|
|
162
|
+
process.stderr.write(`❌ ${_PROG}: ${violations.length} producer(s) do not end in closure\n`);
|
|
163
|
+
for (const v of violations) process.stderr.write(` ${v.file} — ${v.reason}\n`);
|
|
164
|
+
return 1;
|
|
165
|
+
}
|
|
166
|
+
if (!quiet) {
|
|
167
|
+
process.stdout.write(
|
|
168
|
+
`✅ ${_PROG}: ${producers.length} roadmap producer(s), all ending in closure\n`,
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
return 0;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** Both directions in-process: a producer without closure reds, one with it does not. */
|
|
175
|
+
function _selfTest(): number {
|
|
176
|
+
const withClosure = '---\nname: x\nproduces_roadmap: true\n---\n\nRun `/challenge-me closure`.\n';
|
|
177
|
+
const without = '---\nname: x\nproduces_roadmap: true\n---\n\nHand the plan back.\n';
|
|
178
|
+
const notAProducer = '---\nname: x\n---\n\nHand the plan back.\n';
|
|
179
|
+
const failures: string[] = [];
|
|
180
|
+
if (checkFile('a.md', without).length === 0) failures.push('a producer without closure did not red');
|
|
181
|
+
if (checkFile('b.md', withClosure).length !== 0) failures.push('a producer with closure red');
|
|
182
|
+
if (checkFile('c.md', notAProducer).length !== 0) failures.push('a non-producer was judged');
|
|
183
|
+
if (failures.length) {
|
|
184
|
+
for (const f of failures) process.stderr.write(`❌ ${_PROG} --self-test: ${f}\n`);
|
|
185
|
+
return 1;
|
|
186
|
+
}
|
|
187
|
+
process.stdout.write(`✅ ${_PROG} --self-test: both directions hold\n`);
|
|
188
|
+
return 0;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function _isCliEntry(): boolean {
|
|
192
|
+
if (!process.argv[1]) return false;
|
|
193
|
+
try {
|
|
194
|
+
return fs.realpathSync(_HERE) === fs.realpathSync(path.resolve(process.argv[1]));
|
|
195
|
+
} catch {
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (_isCliEntry() || process.argv[1] === _HERE) {
|
|
201
|
+
process.exitCode = main();
|
|
202
|
+
}
|
|
@@ -38,6 +38,7 @@ const REPO_ROOT = path.resolve(path.dirname(_HERE), '..', '..');
|
|
|
38
38
|
|
|
39
39
|
const OVERRIDES_FILE = path.join(REPO_ROOT, 'docs', 'contracts', 'iron-law-overrides.txt');
|
|
40
40
|
const TREND_FILE = path.join(REPO_ROOT, 'agents', 'runtime', '.rule-budget-history.jsonl');
|
|
41
|
+
const AUTO_BUDGET_FILE = path.join(REPO_ROOT, 'src', 'config', 'auto-rule-budget.json');
|
|
41
42
|
|
|
42
43
|
// Council R2 amendments (2026-05-06) — see docs/contracts/kernel-membership.md § 5.1.
|
|
43
44
|
// Per-rule cap raised 1.5k → 2.5k; warning band raised 1.2k → 2.0k.
|
|
@@ -59,6 +60,8 @@ export interface RuleMeasure {
|
|
|
59
60
|
lines: number;
|
|
60
61
|
tokens_gpt: number;
|
|
61
62
|
tokens_claude: number;
|
|
63
|
+
/** Iron-Law headings in the body — the obligation count a char count hides. */
|
|
64
|
+
iron_laws: number;
|
|
62
65
|
}
|
|
63
66
|
|
|
64
67
|
export interface Aggregate {
|
|
@@ -80,6 +83,7 @@ export interface Aggregate {
|
|
|
80
83
|
per_rule_hard: number;
|
|
81
84
|
per_rule_target: number;
|
|
82
85
|
per_rule_override_ceiling: number;
|
|
86
|
+
iron_law_total: number;
|
|
83
87
|
oversize_rules: RuleMeasure[];
|
|
84
88
|
top5_largest: RuleMeasure[];
|
|
85
89
|
}
|
|
@@ -130,9 +134,32 @@ export function measure_rule(p: string): RuleMeasure {
|
|
|
130
134
|
lines: _count(body, '\n'),
|
|
131
135
|
tokens_gpt: token_count.gpt_tokens(body).tokens,
|
|
132
136
|
tokens_claude: token_count.claude_tokens(body).tokens,
|
|
137
|
+
iron_laws: count_iron_laws(body),
|
|
133
138
|
};
|
|
134
139
|
}
|
|
135
140
|
|
|
141
|
+
/**
|
|
142
|
+
* Count Iron-Law HEADINGS in a rule body.
|
|
143
|
+
*
|
|
144
|
+
* road-to-design-fidelity-proof Phase 3.2. A rule is not an instruction:
|
|
145
|
+
* `token-efficiency` carries five Iron Laws in one file, so a file count and a
|
|
146
|
+
* char count both understate what a model is asked to hold at once. The
|
|
147
|
+
* instruction-following literature measures against the number of SIMULTANEOUS
|
|
148
|
+
* constraints, and an Iron-Law heading is the closest proxy this tree can count
|
|
149
|
+
* deterministically.
|
|
150
|
+
*
|
|
151
|
+
* Heading forms accepted, matching `preservation-guard`'s own definition: any
|
|
152
|
+
* level, optional `The`, singular or plural, optional trailing number or
|
|
153
|
+
* qualifier (`## Iron Law 2`, `## Iron Law — Gate`). A prose mention is NOT a
|
|
154
|
+
* heading, and a heading that merely contains the words later (`## Why the Iron
|
|
155
|
+
* Law exists`) is not one either — the phrase must open the heading text, or
|
|
156
|
+
* every retrospective paragraph would inflate the count.
|
|
157
|
+
*/
|
|
158
|
+
export function count_iron_laws(body: string): number {
|
|
159
|
+
const re = /^#{1,6}[ \t]+(?:The[ \t]+)?Iron[ \t]+Laws?\b/gim;
|
|
160
|
+
return (body.match(re) ?? []).length;
|
|
161
|
+
}
|
|
162
|
+
|
|
136
163
|
/**
|
|
137
164
|
* Collect rule measurements from every source root (multi-root aware).
|
|
138
165
|
* Deduplicates on logical rule id (stem) — first root wins. Mirrors
|
|
@@ -198,6 +225,7 @@ export function aggregate(rules: RuleMeasure[]): Aggregate {
|
|
|
198
225
|
per_rule_hard: PER_RULE_HARD,
|
|
199
226
|
per_rule_target: PER_RULE_TARGET,
|
|
200
227
|
per_rule_override_ceiling: PER_RULE_OVERRIDE_CEILING,
|
|
228
|
+
iron_law_total: _sum(rules.map((r) => r.iron_laws)),
|
|
201
229
|
oversize_rules: rules
|
|
202
230
|
.filter((r) => r.chars > PER_RULE_HARD)
|
|
203
231
|
.sort((a, b) => _cmp([-a.chars, a.id], [-b.chars, b.id])),
|
|
@@ -324,6 +352,59 @@ export function kernel_budget_check(
|
|
|
324
352
|
return [0, out];
|
|
325
353
|
}
|
|
326
354
|
|
|
355
|
+
export interface AutoBudgetConfig {
|
|
356
|
+
baseline_chars: number;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/** Read the auto-bucket baseline. Throws rather than defaulting: a ratchet that
|
|
360
|
+
* silently falls back to "no bound" is a permanently green gate. */
|
|
361
|
+
export function load_auto_budget(file: string = AUTO_BUDGET_FILE): AutoBudgetConfig {
|
|
362
|
+
const raw = JSON.parse(fs.readFileSync(file, 'utf-8')) as { baseline_chars?: unknown };
|
|
363
|
+
if (typeof raw.baseline_chars !== 'number') {
|
|
364
|
+
throw new Error(`${file}: baseline_chars must be a number`);
|
|
365
|
+
}
|
|
366
|
+
return { baseline_chars: raw.baseline_chars };
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Enforce the `auto`-bucket growth ratchet. Returns `[exit_code, report_lines]`.
|
|
371
|
+
*
|
|
372
|
+
* road-to-design-fidelity-proof Phase 3.1. `kernel_budget_check` above bounds
|
|
373
|
+
* nine rules; this bounds the other 107, which carry ~93 % of the estate's rule
|
|
374
|
+
* prose and grew against nothing. Shrink-only: growth fails, a shrink passes and
|
|
375
|
+
* says how much slack it created, so the number walks down rather than becoming
|
|
376
|
+
* unused headroom.
|
|
377
|
+
*
|
|
378
|
+
* The Iron-Law total is REPORTED, never gated. No measurement in this tree says
|
|
379
|
+
* how many simultaneous obligations this layer can carry, and a bound nobody
|
|
380
|
+
* measured would publish a guess as a finding.
|
|
381
|
+
*/
|
|
382
|
+
export function auto_budget_check(agg: Aggregate, cfg: AutoBudgetConfig): [number, string[]] {
|
|
383
|
+
const out: string[] = [];
|
|
384
|
+
const delta = agg.auto_chars - cfg.baseline_chars;
|
|
385
|
+
const signed = delta >= 0 ? `+${delta}` : String(delta);
|
|
386
|
+
out.push(
|
|
387
|
+
`auto-bucket: ${agg.auto_chars} / ${cfg.baseline_chars} chars ` +
|
|
388
|
+
`(${agg.auto_count} rules, ${signed} vs baseline)`,
|
|
389
|
+
);
|
|
390
|
+
out.push(`iron-law total: ${agg.iron_law_total} heading(s) — reported, not gated`);
|
|
391
|
+
out.push('');
|
|
392
|
+
if (delta > 0) {
|
|
393
|
+
out.push(`\u274c auto budget check: the auto bucket grew ${signed} chars`);
|
|
394
|
+
out.push(
|
|
395
|
+
' The baseline may only move DOWN. Walk the bucket back, or state the ' +
|
|
396
|
+
'compensating reduction — raising it to clear this is config weakening.',
|
|
397
|
+
);
|
|
398
|
+
return [1, out];
|
|
399
|
+
}
|
|
400
|
+
out.push(
|
|
401
|
+
delta === 0
|
|
402
|
+
? '\u2705 auto budget check: pass (at the baseline)'
|
|
403
|
+
: `\u2705 auto budget check: pass (${signed} chars of slack — ratchet it down)`,
|
|
404
|
+
);
|
|
405
|
+
return [0, out];
|
|
406
|
+
}
|
|
407
|
+
|
|
327
408
|
/**
|
|
328
409
|
* Append a daily snapshot to agents/runtime/.rule-budget-history.jsonl.
|
|
329
410
|
* Idempotent per UTC day. Mirrors `trend_append`. Returns `[exit, msg]`.
|
|
@@ -363,19 +444,22 @@ export function trend_append(agg: Aggregate): [number, string] {
|
|
|
363
444
|
interface Args {
|
|
364
445
|
json: boolean;
|
|
365
446
|
kernelBudgetCheck: boolean;
|
|
447
|
+
autoBudgetCheck: boolean;
|
|
366
448
|
trendAppend: boolean;
|
|
367
449
|
}
|
|
368
450
|
|
|
369
451
|
function parse_args(argv: string[]): Args {
|
|
370
452
|
let json = false;
|
|
371
453
|
let kernelBudgetCheck = false;
|
|
454
|
+
let autoBudgetCheck = false;
|
|
372
455
|
let trendAppend = false;
|
|
373
456
|
for (const a of argv) {
|
|
374
457
|
if (a === '--json') json = true;
|
|
375
458
|
else if (a === '--kernel-budget-check') kernelBudgetCheck = true;
|
|
459
|
+
else if (a === '--auto-budget-check') autoBudgetCheck = true;
|
|
376
460
|
else if (a === '--trend-append') trendAppend = true;
|
|
377
461
|
}
|
|
378
|
-
return { json, kernelBudgetCheck, trendAppend };
|
|
462
|
+
return { json, kernelBudgetCheck, autoBudgetCheck, trendAppend };
|
|
379
463
|
}
|
|
380
464
|
|
|
381
465
|
export function main(argv: string[] = process.argv.slice(2)): number {
|
|
@@ -384,10 +468,22 @@ export function main(argv: string[] = process.argv.slice(2)): number {
|
|
|
384
468
|
const rules = collect();
|
|
385
469
|
const agg = aggregate(rules);
|
|
386
470
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
471
|
+
// Both budget flags may be passed in one invocation, and the CI step does
|
|
472
|
+
// exactly that — a second task step would be a new gate `check_ci_local_parity`
|
|
473
|
+
// has to be told about, for two checks over one measurement.
|
|
474
|
+
if (args.kernelBudgetCheck || args.autoBudgetCheck) {
|
|
475
|
+
let code = 0;
|
|
476
|
+
if (args.kernelBudgetCheck) {
|
|
477
|
+
const overrides = load_overrides();
|
|
478
|
+
const [kCode, report] = kernel_budget_check(rules, agg, overrides);
|
|
479
|
+
process.stdout.write(report.join('\n') + '\n');
|
|
480
|
+
code = Math.max(code, kCode);
|
|
481
|
+
}
|
|
482
|
+
if (args.autoBudgetCheck) {
|
|
483
|
+
const [aCode, report] = auto_budget_check(agg, load_auto_budget());
|
|
484
|
+
process.stdout.write(report.join('\n') + '\n');
|
|
485
|
+
code = Math.max(code, aCode);
|
|
486
|
+
}
|
|
391
487
|
return code;
|
|
392
488
|
}
|
|
393
489
|
|