@event4u/agent-config 16.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 +297 -137
- 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 +74 -27
- 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 +47 -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/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/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-H32DGUJH.js → chunk-P6ZHP5W2.js} +1 -1
- 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-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 +90 -56
- package/dist/cli-delegate/cmd_doctor.js +7 -5
- package/dist/cli-delegate/cmd_explain.js +2 -2
- 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 +4 -4
- 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 +2 -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 +2 -2
- 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 +1 -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 +85 -38
- 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 +1832 -1007
- 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 +2007 -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 +398 -39
- 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_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/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 +21 -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/loop-surfaces.yaml +215 -0
- package/src/config/platform-anchor.json +3 -2
- 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/_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/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/forge_protection.ts +267 -0
- package/src/scripts/_lib/hook_platform_keys.ts +27 -0
- 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/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/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/rides_along.ts +102 -0
- package/src/scripts/_lib/settings_renamed_keys.ts +82 -0
- package/src/scripts/_lib/test_delta.ts +166 -0
- package/src/scripts/_lib/test_provenance.ts +171 -0
- 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_enforcement_matrix.ts +624 -0
- package/src/scripts/check_gate_reachability.ts +173 -10
- package/src/scripts/check_generator_sync.ts +954 -0
- package/src/scripts/check_preamble_payload_budget.ts +75 -2
- package/src/scripts/check_release_highlights.ts +33 -1
- package/src/scripts/check_release_holds.ts +567 -0
- 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 +88 -9
- package/src/scripts/hooks/concern_registry.ts +4 -0
- package/src/scripts/hooks/design_pass_hook.ts +128 -3
- 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/rule_inject_hook.ts +49 -1
- package/src/scripts/hooks/run_continuation_hook.ts +17 -20
- package/src/scripts/hooks_doctor.ts +85 -0
- package/src/scripts/hooks_status.ts +19 -0
- package/src/scripts/install.ts +106 -206
- package/src/scripts/janitor.ts +7 -0
- 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/new_roadmap.ts +37 -0
- package/src/scripts/orchestration_record.ts +0 -5
- package/src/scripts/release.ts +14 -98
- package/src/scripts/release_drill.ts +267 -1
- package/src/scripts/release_publication.ts +51 -0
- package/src/scripts/report_enforcement_drift.ts +566 -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/trigger_eval_grandfather.json +0 -1
- package/src/scripts/ui_conformance_probe.ts +622 -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
|
@@ -49,13 +49,20 @@ import * as path from 'node:path';
|
|
|
49
49
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
50
50
|
|
|
51
51
|
import {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
} from './_lib/rule_injection.js';
|
|
52
|
+
corpusShapeProblems,
|
|
53
|
+
slotFireSizes as sampleSlotFireSizes,
|
|
54
|
+
type SlotFireSizes,
|
|
55
|
+
} from './_lib/activation_payload.js';
|
|
56
|
+
import { loadRouter, pathOnlyRuleIds } from './_lib/rule_injection.js';
|
|
57
57
|
import { CAP_BYTES } from './hooks/rule_inject_hook.js';
|
|
58
58
|
|
|
59
|
+
// Re-exported rather than redefined: this module was their only home until the
|
|
60
|
+
// payload gate needed the same sample, and two copies is how two numbers start
|
|
61
|
+
// disagreeing. `corpusShapeProblems` and `SlotFireSizes` are imported above
|
|
62
|
+
// because this module's own code uses them; these two it only passes through.
|
|
63
|
+
export { percentile, readCorpusPositives } from './_lib/activation_payload.js';
|
|
64
|
+
export { corpusShapeProblems, type SlotFireSizes };
|
|
65
|
+
|
|
59
66
|
const _HERE = fileURLToPath(import.meta.url);
|
|
60
67
|
export const REPO_ROOT = path.resolve(path.dirname(_HERE), '..', '..');
|
|
61
68
|
export const ARTIFACT_REL = path.join(
|
|
@@ -149,8 +156,13 @@ export const HOST_SURFACES: readonly HostSurface[] = [
|
|
|
149
156
|
},
|
|
150
157
|
{
|
|
151
158
|
host: 'codex', surface: '.codex/agent-config.md', perRuleTree: false,
|
|
152
|
-
writer: 'src/scripts/install.ts:
|
|
153
|
-
|
|
159
|
+
writer: 'src/scripts/install.ts:1432',
|
|
160
|
+
// Scoped to `.codex` rather than the bare filename: nine other lines in
|
|
161
|
+
// `install.ts` write an `agent-config.md` for some other host, so the
|
|
162
|
+
// unscoped anchor would have accepted a drift onto any of them — the
|
|
163
|
+
// bounds-test-wearing-a-provenance-test's-name failure this field exists
|
|
164
|
+
// to close, one level down.
|
|
165
|
+
anchor: '\'.codex\', \'agent-config.md\'',
|
|
154
166
|
note: 'written by the installer, not by `condense`; absent in this checkout',
|
|
155
167
|
},
|
|
156
168
|
];
|
|
@@ -431,155 +443,17 @@ export function renderArtifact(root: string, pin: string): string {
|
|
|
431
443
|
return L.join('\n');
|
|
432
444
|
}
|
|
433
445
|
|
|
434
|
-
/** One positive prompt of the frozen corpus, with the open files it declares. */
|
|
435
|
-
interface CorpusPrompt {
|
|
436
|
-
prompt: string;
|
|
437
|
-
openFiles: string[] | null;
|
|
438
|
-
}
|
|
439
|
-
|
|
440
446
|
/**
|
|
441
|
-
*
|
|
447
|
+
* The activation-charge sample at the concern's own cap.
|
|
442
448
|
*
|
|
443
|
-
*
|
|
444
|
-
*
|
|
445
|
-
*
|
|
446
|
-
*
|
|
447
|
-
*
|
|
448
|
-
* measurement that governs a budget must fail loudly on a shape it cannot read
|
|
449
|
-
* rather than under-count, so the CLI refuses on a non-empty result here.
|
|
450
|
-
*
|
|
451
|
-
* Reported as a shape problem rather than fixed by widening the parser: this
|
|
452
|
-
* script must not grow a second YAML implementation, and the corpus is frozen,
|
|
453
|
-
* so the honest answer to an unreadable shape is to say which file carries it.
|
|
454
|
-
*/
|
|
455
|
-
export function corpusShapeProblems(root: string): string[] {
|
|
456
|
-
const dir = path.join(root, 'tests', 'eval', 'routing-matrix');
|
|
457
|
-
const problems: string[] = [];
|
|
458
|
-
if (!fs.existsSync(dir)) return problems;
|
|
459
|
-
for (const f of fs.readdirSync(dir).filter((n) => n.endsWith('.yaml')).sort()) {
|
|
460
|
-
let inPositives = false;
|
|
461
|
-
let lineNo = 0;
|
|
462
|
-
for (const raw of fs.readFileSync(path.join(dir, f), 'utf-8').split('\n')) {
|
|
463
|
-
lineNo += 1;
|
|
464
|
-
if (/^positives:/u.test(raw)) { inPositives = true; continue; }
|
|
465
|
-
if (/^near_misses:/u.test(raw)) { inPositives = false; continue; }
|
|
466
|
-
if (!inPositives) continue;
|
|
467
|
-
if (/^\s*-\s*prompt:/u.test(raw) && !/^\s*-\s*prompt:\s*"(.*)"\s*$/u.test(raw)) {
|
|
468
|
-
problems.push(
|
|
469
|
-
`${f}:${String(lineNo)}: a \`- prompt:\` this parser cannot read — only a ` +
|
|
470
|
-
`double-quoted same-line scalar is accepted: ${JSON.stringify(raw.trim())}`,
|
|
471
|
-
);
|
|
472
|
-
continue;
|
|
473
|
-
}
|
|
474
|
-
if (/^\s*-\s*/u.test(raw) && !/^\s*-\s*(prompt|command|open_files):/u.test(raw)
|
|
475
|
-
&& raw.trim() !== '-' && raw.trim() !== '') {
|
|
476
|
-
// A bare sequence item under `positives:` is a shape with no
|
|
477
|
-
// `prompt:` key on its first line — folded or nested.
|
|
478
|
-
if (!/^\s{4,}/u.test(raw)) {
|
|
479
|
-
problems.push(
|
|
480
|
-
`${f}:${String(lineNo)}: a positives entry whose first line carries no ` +
|
|
481
|
-
`\`prompt:\` key: ${JSON.stringify(raw.trim())}`,
|
|
482
|
-
);
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
if (/^\s*open_files:\s*$/u.test(raw)) {
|
|
486
|
-
problems.push(
|
|
487
|
-
`${f}:${String(lineNo)}: a BLOCK-sequence \`open_files:\` — only the inline ` +
|
|
488
|
-
'`[...]` form is read, so this entry\'s files would be dropped',
|
|
489
|
-
);
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
return problems;
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
/** Every positive prompt in the frozen routing-matrix corpus. Near-misses are not fires. */
|
|
497
|
-
export function readCorpusPositives(root: string): CorpusPrompt[] {
|
|
498
|
-
const dir = path.join(root, 'tests', 'eval', 'routing-matrix');
|
|
499
|
-
const out: CorpusPrompt[] = [];
|
|
500
|
-
if (!fs.existsSync(dir)) return out;
|
|
501
|
-
for (const f of fs.readdirSync(dir).filter((n) => n.endsWith('.yaml')).sort()) {
|
|
502
|
-
let inPositives = false;
|
|
503
|
-
let cur: CorpusPrompt | null = null;
|
|
504
|
-
for (const raw of fs.readFileSync(path.join(dir, f), 'utf-8').split('\n')) {
|
|
505
|
-
if (/^positives:/u.test(raw)) { inPositives = true; continue; }
|
|
506
|
-
if (/^near_misses:/u.test(raw)) { inPositives = false; continue; }
|
|
507
|
-
if (!inPositives) continue;
|
|
508
|
-
const p = /^\s*-\s*prompt:\s*"(.*)"\s*$/u.exec(raw);
|
|
509
|
-
if (p !== null) {
|
|
510
|
-
cur = { prompt: p[1] as string, openFiles: null };
|
|
511
|
-
out.push(cur);
|
|
512
|
-
continue;
|
|
513
|
-
}
|
|
514
|
-
const of = /^\s*open_files:\s*\[(.*)\]\s*$/u.exec(raw);
|
|
515
|
-
if (of !== null && cur !== null) {
|
|
516
|
-
cur.openFiles = (of[1] as string)
|
|
517
|
-
.split(',')
|
|
518
|
-
.map((x) => x.trim().replace(/^["']|["']$/gu, ''))
|
|
519
|
-
.filter((x) => x !== '');
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
return out;
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
/** Nearest-rank percentile over an unsorted sample. Empty sample → 0. */
|
|
527
|
-
export function percentile(xs: readonly number[], q: number): number {
|
|
528
|
-
if (xs.length === 0) return 0;
|
|
529
|
-
const s = [...xs].sort((a, b) => a - b);
|
|
530
|
-
return s[Math.min(s.length - 1, Math.floor(q * (s.length - 1)))] as number;
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
export interface SlotFireSizes {
|
|
534
|
-
readonly slot: string;
|
|
535
|
-
readonly fires: number;
|
|
536
|
-
readonly p50: number;
|
|
537
|
-
readonly p90: number;
|
|
538
|
-
readonly max: number;
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
/**
|
|
542
|
-
* Gate-open per-fire emission sizes for the delivery concern, per slot
|
|
543
|
-
* (road-to-delivery-for-every-host 3.1).
|
|
544
|
-
*
|
|
545
|
-
* Measured through the SAME selection the runtime concern uses —
|
|
546
|
-
* `matchTierRules` + `selectForInjection` at the concern's own `CAP_BYTES` —
|
|
547
|
-
* rather than through a second model of it. An offline figure computed by a
|
|
548
|
-
* different matcher would price a set the concern does not deliver.
|
|
549
|
-
*
|
|
550
|
-
* `pre_compact` is 0 by construction rather than by measurement: that branch of
|
|
551
|
-
* `rule_inject_hook` clears the seen-set and returns allow without writing to
|
|
552
|
-
* stdout, so there is no emission to sample.
|
|
449
|
+
* The sampling itself moved to `_lib/activation_payload.ts` when the payload
|
|
450
|
+
* gate needed the same figure (`road-to-the-delivery-flip-that-tells-the-truth`
|
|
451
|
+
* 3.1). This wrapper supplies `CAP_BYTES` so the report's own callers keep the
|
|
452
|
+
* one-argument form, and the helpers below are re-exported so there is still
|
|
453
|
+
* exactly one implementation of each.
|
|
553
454
|
*/
|
|
554
455
|
export function slotFireSizes(root: string): SlotFireSizes[] {
|
|
555
|
-
|
|
556
|
-
const prompts = readCorpusPositives(root);
|
|
557
|
-
const sample = (mode: 'prompt' | 'file'): number[] => {
|
|
558
|
-
const out: number[] = [];
|
|
559
|
-
for (const r of prompts) {
|
|
560
|
-
if (mode === 'file' && (r.openFiles === null || r.openFiles.length === 0)) continue;
|
|
561
|
-
const matches =
|
|
562
|
-
mode === 'prompt'
|
|
563
|
-
? matchTierRules(router, r.prompt, null, null)
|
|
564
|
-
: matchTierRules(router, '', r.openFiles, null);
|
|
565
|
-
if (matches.length === 0) continue;
|
|
566
|
-
const sel = selectForInjection(root, matches, CAP_BYTES);
|
|
567
|
-
if (sel.selected.length > 0) out.push(sel.bytes);
|
|
568
|
-
}
|
|
569
|
-
return out;
|
|
570
|
-
};
|
|
571
|
-
const row = (slot: string, xs: number[]): SlotFireSizes => ({
|
|
572
|
-
slot,
|
|
573
|
-
fires: xs.length,
|
|
574
|
-
p50: percentile(xs, 0.5),
|
|
575
|
-
p90: percentile(xs, 0.9),
|
|
576
|
-
max: xs.length === 0 ? 0 : Math.max(...xs),
|
|
577
|
-
});
|
|
578
|
-
return [
|
|
579
|
-
row('user_prompt_submit', sample('prompt')),
|
|
580
|
-
row('pre_tool_use', sample('file')),
|
|
581
|
-
row('pre_compact', []),
|
|
582
|
-
];
|
|
456
|
+
return sampleSlotFireSizes(root, CAP_BYTES);
|
|
583
457
|
}
|
|
584
458
|
|
|
585
459
|
function headSha(root: string): string {
|
|
@@ -101,6 +101,29 @@
|
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
},
|
|
104
|
+
"delivery": {
|
|
105
|
+
"type": "object",
|
|
106
|
+
"additionalProperties": true,
|
|
107
|
+
"properties": {
|
|
108
|
+
"merge": {
|
|
109
|
+
"type": "string",
|
|
110
|
+
"enum": ["off", "on-green"],
|
|
111
|
+
"default": "off",
|
|
112
|
+
"description": "Whether a run may merge the pull request it produced. off (default) = the run ends at mergeable-green-and-open and says so. on-green = merge is permitted, and only when an object-bound grant covering {op: prod_merge, target: <base>} exists and the final head is required-check-green, target-current and tamper-checked (ADR-268 section 3). A precondition, never the authorisation by itself; forge auto-merge is the mechanism, so branch protection stays the gate."
|
|
113
|
+
},
|
|
114
|
+
"wait_for_ci": {
|
|
115
|
+
"type": "boolean",
|
|
116
|
+
"default": true,
|
|
117
|
+
"description": "Whether the run stays alive until the required checks settle. true (default) = the run drives CI and reports the settled verdict. false = the run ends once the branch is pushed and the PR is open. Independent of merge: a run may wait for CI without being allowed to merge."
|
|
118
|
+
},
|
|
119
|
+
"pr_topology": {
|
|
120
|
+
"type": "string",
|
|
121
|
+
"enum": ["single", "stacked"],
|
|
122
|
+
"default": "single",
|
|
123
|
+
"description": "How a mission's work is shaped into pull requests. single (default) = one branch, one pull request. stacked = a dependent series. stacked is never chosen by the agent and never asked about at roadmap creation — the owner plans it in roadmap frontmatter or it does not happen."
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
},
|
|
104
127
|
"screenshots": {
|
|
105
128
|
"type": "object",
|
|
106
129
|
"additionalProperties": true,
|
|
@@ -103,6 +103,10 @@
|
|
|
103
103
|
"pattern": "^[a-z][a-z0-9-]*$",
|
|
104
104
|
"description": "Sub-command identifier within the cluster (e.g. `ci` for `/fix ci`)."
|
|
105
105
|
},
|
|
106
|
+
"produces_roadmap": {
|
|
107
|
+
"type": "boolean",
|
|
108
|
+
"description": "This command produces a roadmap, so it ends in the plan-closure pass (`/challenge-me closure`). The declaration replaces the hard-coded entrance list that lived inside three command bodies and left the other five producers uncovered with nothing saying so. `lint_roadmap_producers` reds a command that declares it and carries no reference to the closure pass. Omit the key for commands that produce no plan."
|
|
109
|
+
},
|
|
106
110
|
"superseded_by": {
|
|
107
111
|
"type": "string",
|
|
108
112
|
"pattern": "^[a-z][a-z0-9-]*( (--[a-z][a-z0-9-]*|[a-z][a-z0-9-]*))?$",
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* Who owns a piece of scope growth discovered mid-mission.
|
|
4
|
+
*
|
|
5
|
+
* The size question — *is this small and aligned enough to do now* — already
|
|
6
|
+
* has an answer in the remediation ladder. This is the other axis, and the two
|
|
7
|
+
* are independent: something small and council-owned is still not the agent's
|
|
8
|
+
* to decide, and something agent-owned and large is still bounded by the
|
|
9
|
+
* smallest-diff rule.
|
|
10
|
+
*
|
|
11
|
+
* Four verdicts, and the last one is the important one:
|
|
12
|
+
*
|
|
13
|
+
* `agent` done inline, recorded as a scope delta in the PR body, never
|
|
14
|
+
* asked about.
|
|
15
|
+
* `council` routed through the ownership ladder; the verdict becomes a
|
|
16
|
+
* `## Decisions` row. It does NOT reach the owner, however
|
|
17
|
+
* consequential — a technical decision does not become
|
|
18
|
+
* owner-owned because it is hard.
|
|
19
|
+
* `owner` the work changes what the product or the business does, or it
|
|
20
|
+
* needs a typed op for which no grant exists. Two rows, closed.
|
|
21
|
+
* `follow-up` not scope growth at all. A larger unrelated opportunity
|
|
22
|
+
* becomes its own artifact and the mission does not expand to
|
|
23
|
+
* hold it — the failure that looks like diligence is a mission
|
|
24
|
+
* that absorbs every good idea it meets and delivers none.
|
|
25
|
+
*
|
|
26
|
+
* `unknown` is a real verdict and is deliberately NOT folded into `agent`:
|
|
27
|
+
* growth nothing classifies is growth nobody decided, and defaulting it to the
|
|
28
|
+
* cheapest rung is how an owner question becomes an agent one silently.
|
|
29
|
+
*
|
|
30
|
+
* Exit codes: 0 classified · 1 unknown · 2 bad argv.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
import * as fs from 'node:fs';
|
|
34
|
+
import * as path from 'node:path';
|
|
35
|
+
import process from 'node:process';
|
|
36
|
+
import { fileURLToPath } from 'node:url';
|
|
37
|
+
|
|
38
|
+
const _HERE = fileURLToPath(import.meta.url);
|
|
39
|
+
const _PROG = 'scope_growth';
|
|
40
|
+
|
|
41
|
+
export type Verdict = 'agent' | 'council' | 'owner' | 'follow-up' | 'unknown';
|
|
42
|
+
|
|
43
|
+
export interface Rule {
|
|
44
|
+
readonly verdict: Verdict;
|
|
45
|
+
readonly kind: string;
|
|
46
|
+
readonly re: RegExp;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Ordered, and the order is the contract: `owner` and `follow-up` are tested
|
|
51
|
+
* BEFORE `agent`, so a row that matches both ("a missing test — in a subsystem
|
|
52
|
+
* this mission never touched") resolves to the more conservative rung rather
|
|
53
|
+
* than to the first cheap match.
|
|
54
|
+
*/
|
|
55
|
+
export const RULES: readonly Rule[] = [
|
|
56
|
+
// --- owner: two rows, closed ------------------------------------------
|
|
57
|
+
{
|
|
58
|
+
verdict: 'owner',
|
|
59
|
+
kind: 'product-or-business-change',
|
|
60
|
+
re: /\b(?:new user-visible|changes what the product|changes what the business|a price|pricing|a public commitment|a policy change)\b/i,
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
verdict: 'owner',
|
|
64
|
+
kind: 'typed-op-without-grant',
|
|
65
|
+
re: /\b(?:needs a typed op|no grant exists|merge to main|force-push|deploy to prod(?:uction)?|rotate the secret)\b/i,
|
|
66
|
+
},
|
|
67
|
+
// --- follow-up: unrelated, however good -------------------------------
|
|
68
|
+
{
|
|
69
|
+
verdict: 'follow-up',
|
|
70
|
+
kind: 'larger-unrelated',
|
|
71
|
+
re: /\b(?:unrelated|another subsystem|a subsystem this .{0,30}never touched|out of scope|deserves its own)\b/i,
|
|
72
|
+
},
|
|
73
|
+
// --- council: technical, contested ------------------------------------
|
|
74
|
+
{
|
|
75
|
+
verdict: 'council',
|
|
76
|
+
kind: 'larger-internal-re-cut',
|
|
77
|
+
re: /\b(?:re-?cut|restructure the module|reshape the boundary)\b/i,
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
verdict: 'council',
|
|
81
|
+
kind: 'two-equal-strategies',
|
|
82
|
+
re: /\b(?:two equal|two valid|either strategy|no evidence between them)\b/i,
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
verdict: 'council',
|
|
86
|
+
kind: 'risky-compatibility-design',
|
|
87
|
+
re: /\b(?:compatibility risk|backwards[- ]incompat|breaking change)\b/i,
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
verdict: 'council',
|
|
91
|
+
kind: 'unclear-boundary',
|
|
92
|
+
re: /\b(?:unclear boundary|where the boundary)\b/i,
|
|
93
|
+
},
|
|
94
|
+
// --- agent: six rows, closed ------------------------------------------
|
|
95
|
+
{
|
|
96
|
+
verdict: 'agent',
|
|
97
|
+
kind: 'necessary-internal-refactor',
|
|
98
|
+
re: /\b(?:necessary (?:internal )?refactor|cannot land (?:correctly )?without)\b/i,
|
|
99
|
+
},
|
|
100
|
+
{ verdict: 'agent', kind: 'missing-test', re: /\bmissing test\b/i },
|
|
101
|
+
{
|
|
102
|
+
verdict: 'agent',
|
|
103
|
+
kind: 'regression-on-touched-path',
|
|
104
|
+
re: /\bregression\b[^.]{0,60}\btouched\b|\btouched\b[^.]{0,60}\bregression\b/i,
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
verdict: 'agent',
|
|
108
|
+
kind: 'small-dependency-adjustment',
|
|
109
|
+
re: /\b(?:small dependency adjustment|patch bump|minor bump)\b/i,
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
verdict: 'agent',
|
|
113
|
+
kind: 'local-api-inside-defined-semantics',
|
|
114
|
+
re: /\b(?:inside (?:the )?(?:already-)?defined semantics|the contract does not move)\b/i,
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
verdict: 'agent',
|
|
118
|
+
kind: 'boy-scout-cleanup',
|
|
119
|
+
re: /\bboy[- ]scout\b/i,
|
|
120
|
+
},
|
|
121
|
+
];
|
|
122
|
+
|
|
123
|
+
export interface Classification {
|
|
124
|
+
readonly verdict: Verdict;
|
|
125
|
+
readonly kind: string;
|
|
126
|
+
/** True when the verdict is done inline and recorded rather than asked. */
|
|
127
|
+
readonly records_scope_delta: boolean;
|
|
128
|
+
/** True when a person is reached at all. */
|
|
129
|
+
readonly asks: boolean;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function classifyGrowth(text: string): Classification {
|
|
133
|
+
for (const r of RULES) {
|
|
134
|
+
if (r.re.test(text)) {
|
|
135
|
+
return {
|
|
136
|
+
verdict: r.verdict,
|
|
137
|
+
kind: r.kind,
|
|
138
|
+
records_scope_delta: r.verdict === 'agent',
|
|
139
|
+
asks: r.verdict === 'owner',
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return { verdict: 'unknown', kind: 'unclassified', records_scope_delta: false, asks: false };
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function _usage(): string {
|
|
147
|
+
return `usage: ${_PROG} [-h] [--self-test] [--json] <description...>\n`;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function main(argv?: readonly string[]): number {
|
|
151
|
+
const args = argv ?? process.argv.slice(2);
|
|
152
|
+
let json = false;
|
|
153
|
+
const words: string[] = [];
|
|
154
|
+
for (const a of args) {
|
|
155
|
+
if (a === '-h' || a === '--help') {
|
|
156
|
+
process.stdout.write(_usage());
|
|
157
|
+
return 0;
|
|
158
|
+
}
|
|
159
|
+
if (a === '--self-test') return _selfTest();
|
|
160
|
+
if (a === '--json') {
|
|
161
|
+
json = true;
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
words.push(a);
|
|
165
|
+
}
|
|
166
|
+
if (!words.length) {
|
|
167
|
+
process.stderr.write(`${_usage()}${_PROG}: error: a description is required\n`);
|
|
168
|
+
return 2;
|
|
169
|
+
}
|
|
170
|
+
const c = classifyGrowth(words.join(' '));
|
|
171
|
+
if (json) {
|
|
172
|
+
process.stdout.write(JSON.stringify(c, null, 2) + '\n');
|
|
173
|
+
} else {
|
|
174
|
+
process.stdout.write(
|
|
175
|
+
`${c.verdict} (${c.kind}) scope-delta=${String(c.records_scope_delta)} asks=${String(c.asks)}\n`,
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
return c.verdict === 'unknown' ? 1 : 0;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function _selfTest(): number {
|
|
182
|
+
const cases: ReadonlyArray<readonly [string, Verdict]> = [
|
|
183
|
+
['a missing test on a path this change touched', 'agent'],
|
|
184
|
+
['a boy-scout cleanup, small and local', 'agent'],
|
|
185
|
+
['two equal technical strategies with no evidence between them', 'council'],
|
|
186
|
+
['this introduces a compatibility risk', 'council'],
|
|
187
|
+
['it needs a typed op and no grant exists', 'owner'],
|
|
188
|
+
['this adds new user-visible semantics', 'owner'],
|
|
189
|
+
['an unrelated refactor that deserves its own roadmap', 'follow-up'],
|
|
190
|
+
['something nobody wrote a rule for', 'unknown'],
|
|
191
|
+
// The ordering case: matches `missing test` AND `unrelated`, and the
|
|
192
|
+
// conservative rung must win or a follow-up silently becomes agent work.
|
|
193
|
+
['a missing test in an unrelated subsystem', 'follow-up'],
|
|
194
|
+
];
|
|
195
|
+
const failures: string[] = [];
|
|
196
|
+
for (const [text, want] of cases) {
|
|
197
|
+
const got = classifyGrowth(text).verdict;
|
|
198
|
+
if (got !== want) failures.push(`"${text}" → ${got}, wanted ${want}`);
|
|
199
|
+
}
|
|
200
|
+
if (failures.length) {
|
|
201
|
+
for (const f of failures) process.stderr.write(`❌ ${_PROG} --self-test: ${f}\n`);
|
|
202
|
+
return 1;
|
|
203
|
+
}
|
|
204
|
+
process.stdout.write(`✅ ${_PROG} --self-test: ${String(cases.length)} case(s) behaved\n`);
|
|
205
|
+
return 0;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function _isCliEntry(): boolean {
|
|
209
|
+
if (!process.argv[1]) return false;
|
|
210
|
+
try {
|
|
211
|
+
return fs.realpathSync(_HERE) === fs.realpathSync(path.resolve(process.argv[1]));
|
|
212
|
+
} catch {
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (_isCliEntry() || process.argv[1] === _HERE) {
|
|
218
|
+
process.exitCode = main();
|
|
219
|
+
}
|