@event4u/agent-config 9.11.0 → 9.13.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 +80 -204
- package/README.md +8 -1
- package/dist/agent-src/commands/fix/ci.md +29 -0
- package/dist/agent-src/commands/pr/create.md +60 -0
- package/dist/agent-src/contexts/authority/kernel-rule-edits.md +18 -2
- package/dist/agent-src/rules/active-remediation.md +0 -2
- package/dist/agent-src/rules/architecture.md +0 -1
- package/dist/agent-src/rules/artifact-drafting-protocol.md +0 -4
- package/dist/agent-src/rules/autonomous-execution.md +1 -2
- package/dist/agent-src/rules/broken-access-control.md +0 -2
- package/dist/agent-src/rules/code-comment-discipline.md +0 -3
- package/dist/agent-src/rules/code-provenance.md +0 -3
- package/dist/agent-src/rules/communication-through-line.md +2 -3
- package/dist/agent-src/rules/content-quoting-floor.md +0 -2
- package/dist/agent-src/rules/context-hygiene.md +1 -3
- package/dist/agent-src/rules/decision-revisit-gate.md +0 -2
- package/dist/agent-src/rules/design-fidelity.md +30 -1
- package/dist/agent-src/rules/domain-adoption-policy.md +0 -3
- package/dist/agent-src/rules/downstream-changes.md +10 -1
- package/dist/agent-src/rules/external-reference-deep-dive.md +0 -7
- package/dist/agent-src/rules/fast-path-marker-visibility.md +0 -1
- package/dist/agent-src/rules/git-history-discipline.md +0 -7
- package/dist/agent-src/rules/guidelines.md +0 -2
- package/dist/agent-src/rules/improve-before-implement.md +4 -2
- package/dist/agent-src/rules/invite-challenge.md +0 -4
- package/dist/agent-src/rules/linked-projects-onboarding-gate.md +0 -2
- package/dist/agent-src/rules/markdown-safe-codeblocks.md +0 -1
- package/dist/agent-src/rules/minimal-safe-diff.md +2 -2
- package/dist/agent-src/rules/missing-tool-handling.md +0 -1
- package/dist/agent-src/rules/no-attribution-footers.md +0 -3
- package/dist/agent-src/rules/no-decorative-emojis-in-git-surfaces.md +8 -5
- package/dist/agent-src/rules/no-pr-progress-comments.md +1 -3
- package/dist/agent-src/rules/no-roadmap-references.md +0 -2
- package/dist/agent-src/rules/output-discipline.md +0 -1
- package/dist/agent-src/rules/prefer-enums-over-literals.md +0 -2
- package/dist/agent-src/rules/preservation-guard.md +0 -3
- package/dist/agent-src/rules/role-mode-adherence.md +0 -1
- package/dist/agent-src/rules/secret-vcs-guard.md +0 -2
- package/dist/agent-src/rules/senior-engineering-discipline.md +0 -2
- package/dist/agent-src/rules/session-canary.md +0 -2
- package/dist/agent-src/rules/size-enforcement.md +0 -5
- package/dist/agent-src/rules/source-confidentiality.md +0 -3
- package/dist/agent-src/rules/source-discovery-gate.md +0 -2
- package/dist/agent-src/rules/think-before-action.md +3 -3
- package/dist/agent-src/rules/token-budget-discipline.md +0 -1
- package/dist/agent-src/rules/token-efficiency.md +1 -2
- package/dist/agent-src/rules/tool-safety.md +0 -1
- package/dist/agent-src/rules/user-interaction.md +0 -3
- package/dist/agent-src/rules/user-interrupt-priority.md +0 -1
- package/dist/agent-src/skills/agent-docs-writing/SKILL.md +8 -0
- package/dist/agent-src/skills/ai-code-blindspots/SKILL.md +1 -0
- package/dist/agent-src/skills/analysis-skill-router/SKILL.md +55 -86
- package/dist/agent-src/skills/character-consistency/SKILL.md +7 -4
- package/dist/agent-src/skills/decision-record/SKILL.md +8 -0
- package/dist/agent-src/skills/design-intelligence/SKILL.md +27 -1
- package/dist/agent-src/skills/design-intelligence/data/font-pairings-reference.csv +74 -74
- package/dist/agent-src/skills/design-intelligence/data/manifest.json +2 -0
- package/dist/agent-src/skills/design-review/SKILL.md +11 -0
- package/dist/agent-src/skills/design-system-capture/reference/design-system-json.md +8 -0
- package/dist/agent-src/skills/design-tokens/scripts/tokens.ts +0 -7
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +34 -3
- package/dist/agent-src/skills/fe-design/SKILL.md +10 -0
- package/dist/agent-src/skills/motion-choreographer/SKILL.md +7 -4
- package/dist/agent-src/skills/overbuild-review-lens/SKILL.md +201 -0
- package/dist/agent-src/skills/performance/SKILL.md +14 -0
- package/dist/agent-src/skills/pixar-storyteller/SKILL.md +8 -5
- package/dist/agent-src/skills/scene-expander/SKILL.md +9 -6
- package/dist/agent-src/skills/supply-chain-intake/SKILL.md +10 -0
- package/dist/agent-src/skills/typography-system/SKILL.md +55 -11
- package/dist/agent-src/skills/ui-apply-generic/SKILL.md +180 -0
- package/dist/agent-src/skills/universal-project-analysis/SKILL.md +14 -37
- package/dist/agent-src/skills/video-director/SKILL.md +9 -6
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +162 -17
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/design.ts +118 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +49 -6
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/review.ts +9 -5
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/stack_bundles.ts +182 -29
- package/dist/agent-src/templates/scripts/work_engine/stack/detect.ts +311 -24
- package/dist/agent-src/templates/scripts/work_engine/state.ts +55 -0
- package/dist/cli-delegate/chunk-523HCFYO.js +90 -0
- package/dist/cli-delegate/{chunk-IR7P7JWA.js → chunk-A3HJ6NTI.js} +271 -59
- package/dist/cli-delegate/chunk-EJYIGZ3T.js +125 -0
- package/dist/cli-delegate/{chunk-RDGRHAAB.js → chunk-HYWSRNUX.js} +6 -86
- package/dist/cli-delegate/{chunk-YMFO6FDN.js → chunk-QFKQLQ7X.js} +313 -81
- package/dist/cli-delegate/{chunk-4SV3XGFA.js → chunk-TEGJU2JX.js} +7 -9
- package/dist/cli-delegate/chunk-TJIAM5FW.js +133 -0
- package/dist/cli-delegate/cmd_conformance.js +4 -7
- package/dist/cli-delegate/cmd_doctor.js +3 -5
- package/dist/cli-delegate/cmd_explain.js +153 -85
- package/dist/cli-delegate/cmd_export.js +5 -3
- package/dist/cli-delegate/cmd_fleet.js +2 -1
- package/dist/cli-delegate/cmd_preflight.js +6 -123
- package/dist/cli-delegate/cmd_prune.js +5 -3
- package/dist/cli-delegate/cmd_settings_migrate.js +5 -3
- package/dist/cli-delegate/cmd_sync.js +5 -3
- package/dist/cli-delegate/cmd_uninstall.js +6 -5
- package/dist/cli-delegate/cmd_validate.js +5 -3
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +116 -72
- 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 +7 -5
- package/dist/discovery/trust-report.md +2 -2
- package/dist/discovery/workspaces.json +6 -4
- package/dist/hooks/dispatch.js +174 -13
- package/dist/install/install.mjs +605 -412
- package/dist/install/ruleInScope.js +123 -0
- package/dist/install/ruleInScope.js.map +1 -0
- package/dist/install/rule_scope.js +2 -2
- package/dist/install/rule_scope.js.map +1 -1
- package/dist/install/wizard-plan.js +10 -1
- package/dist/install/wizard-plan.js.map +1 -1
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +710 -2491
- package/dist/router.json +1 -1
- package/dist/scripts/condense.js +8 -24
- package/dist/scripts/condense.js.map +1 -1
- package/docs/MIGRATION.md +1 -1
- package/docs/guidelines/agent-infra/agent-interaction-and-decision-quality.md +71 -0
- package/docs/guidelines/agent-infra/minimal-safe-diff-mechanics.md +24 -1
- package/docs/guidelines/code-clarity.md +9 -2
- package/docs/guidelines/design-fidelity-mechanics.md +58 -0
- package/llms.txt +63 -27
- package/package.json +4 -4
- package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +162 -17
- package/src/agent-src/templates/scripts/work_engine/directives/ui/design.ts +118 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +49 -6
- package/src/agent-src/templates/scripts/work_engine/directives/ui/review.ts +9 -5
- package/src/agent-src/templates/scripts/work_engine/directives/ui/stack_bundles.ts +182 -29
- package/src/agent-src/templates/scripts/work_engine/stack/detect.ts +311 -24
- package/src/agent-src/templates/scripts/work_engine/state.ts +55 -0
- package/src/config/agent-settings.template.yml +8 -0
- package/src/install/ruleInScope.ts +133 -0
- package/src/install/rule_scope.ts +2 -2
- package/src/install/wizard-plan.ts +11 -1
- package/src/scripts/_lib/counted_probe.ts +142 -0
- package/src/scripts/_lib/global_deploy_inventory.ts +38 -2
- package/src/scripts/_lib/overbuild_lens_contract.ts +196 -0
- package/src/scripts/_lib/release_scope.ts +207 -0
- package/src/scripts/ai_council/stance_tally.ts +37 -2
- package/src/scripts/audit_auto_rules.ts +9 -9
- package/src/scripts/audit_likelihood.ts +3 -3
- package/src/scripts/audit_overlap.ts +2 -2
- package/src/scripts/audit_skill_overlap.ts +233 -95
- package/src/scripts/audit_skill_overlap_allowlist.json +4 -0
- package/src/scripts/build_proof.ts +15 -1
- package/src/scripts/check_dependency_floors.ts +16 -6
- package/src/scripts/check_gate_coverage.ts +6 -6
- package/src/scripts/check_installer_import_purity.ts +295 -0
- package/src/scripts/check_kernel_rule_bundle.ts +5 -4
- package/src/scripts/check_token_quality_golden.ts +0 -18
- package/src/scripts/code_graph/loader.ts +35 -6
- package/src/scripts/compile_router.ts +3 -8
- package/src/scripts/condense.ts +9 -30
- package/src/scripts/explain_run.ts +0 -1
- package/src/scripts/generate_pack_manifests.ts +3 -20
- package/src/scripts/hooks/block_kernel_rule_writes.ts +145 -10
- package/src/scripts/hooks/block_no_verify.ts +101 -0
- package/src/scripts/install-hooks.sh +36 -4
- package/src/scripts/install.ts +210 -5
- package/src/scripts/lint_agent_security.ts +5 -4
- package/src/scripts/lint_framework_leakage_allowlist.json +2 -2
- package/src/scripts/lint_regression.ts +92 -1
- package/src/scripts/lint_skill_descriptions.ts +93 -5
- package/src/scripts/lint_ui_stack_bundles.ts +31 -0
- package/src/scripts/project_thin_rules.ts +2 -2
- package/src/scripts/release.ts +107 -3
- package/src/scripts/resolve_lint_scope.ts +53 -0
- package/src/scripts/router_telemetry.ts +0 -5
- package/src/scripts/runtime_dispatcher.ts +40 -0
- package/src/scripts/schemas/pack.schema.json +1 -5
- package/src/scripts/schemas/rule.schema.json +1 -2
- package/src/scripts/self_review_gate.ts +15 -73
- package/src/scripts/skill_linter.ts +93 -11
- package/src/scripts/sweep_dead_scan_roots.ts +550 -0
- package/src/scripts/trigger_coverage.ts +11 -37
- package/dist/cli-delegate/chunk-7DSAMZFU.js +0 -356
- package/dist/cli-delegate/chunk-BJGXZNPM.js +0 -266
- package/dist/cli-delegate/chunk-TFG57JJM.js +0 -1969
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
model_tier: inherit
|
|
3
3
|
name: video-director
|
|
4
|
-
description: "Use when
|
|
4
|
+
description: "Use when a live-action beat becomes the 11-block cinematic prompt — lens, lighting, negatives. Triggers 'cinematic prompt', 'film-grade scene'. Animated → pixar-storyteller; 12-block → scene-expander."
|
|
5
5
|
personas:
|
|
6
6
|
- hollywood-director
|
|
7
7
|
domain: product
|
|
@@ -124,13 +124,16 @@ Any "no" → revise that block before handing off.
|
|
|
124
124
|
|
|
125
125
|
## Policies
|
|
126
126
|
|
|
127
|
+
Paths, enforcement model, and the full set: the
|
|
128
|
+
[media policy preamble](../../../agents/settings/policies/media/README.md).
|
|
129
|
+
|
|
127
130
|
The 11-block cinematic prompt is live-action shape — real-person and brand-impersonation risks are the highest in the cluster. Before emitting:
|
|
128
131
|
|
|
129
|
-
-
|
|
130
|
-
-
|
|
131
|
-
-
|
|
132
|
-
-
|
|
133
|
-
-
|
|
132
|
+
- **`likeness`** — when the prompt names or visually identifies a real person on camera.
|
|
133
|
+
- **`public-figures`** — when the subject is a recognised public figure.
|
|
134
|
+
- **`brand-impersonation`** — when the prompt copies a journalism / broadcaster / regulated-industry visual identity.
|
|
135
|
+
- **`style`** — when LIGHT / LENS choices are anchored to a named living cinematographer's signature.
|
|
136
|
+
- **`disclosure`** — every distributed live-action AI clip carries the non-removable AI-generation disclosure.
|
|
134
137
|
|
|
135
138
|
Refuse-and-surface at the directorial layer; live-action realism amplifies every policy gap downstream.
|
|
136
139
|
|
|
@@ -39,7 +39,7 @@ schema_version: 1
|
|
|
39
39
|
# CI guard: a release bump of `package.json` must update this value
|
|
40
40
|
# in lockstep — see scripts/check_template_pin_drift.ts (road-to-
|
|
41
41
|
# portable-runtime-and-update-check P3.3).
|
|
42
|
-
agent_config_version: "9.
|
|
42
|
+
agent_config_version: "9.13.0"
|
|
43
43
|
|
|
44
44
|
# --- Project identity ---
|
|
45
45
|
project:
|
|
@@ -17,9 +17,9 @@ import {
|
|
|
17
17
|
StepResult,
|
|
18
18
|
agent_directive,
|
|
19
19
|
} from '../../delivery_state.js';
|
|
20
|
-
import { placeholder_paths } from './design.js';
|
|
20
|
+
import { has_design_system, placeholder_paths, provided_artifact } from './design.js';
|
|
21
21
|
import {
|
|
22
|
-
|
|
22
|
+
is_ambiguous_stack,
|
|
23
23
|
bundle_line,
|
|
24
24
|
unsupported_stack_questions,
|
|
25
25
|
} from './stack_bundles.js';
|
|
@@ -51,6 +51,17 @@ export const AMBIGUITIES: ReadonlyArray<Record<string, string>> = [
|
|
|
51
51
|
'agent directive `ui-apply-<stack>` → skill ' +
|
|
52
52
|
'bundle implements the brief and writes the envelope back',
|
|
53
53
|
},
|
|
54
|
+
{
|
|
55
|
+
code: 'apply_coverage_missing',
|
|
56
|
+
trigger:
|
|
57
|
+
'a provided artifact is in state.ui_design but the ui_apply ' +
|
|
58
|
+
'envelope carries no coverage report, or the report leaves a ' +
|
|
59
|
+
'declared interaction / keyframe / asset unaccounted for',
|
|
60
|
+
resolution:
|
|
61
|
+
'agent writes ui_apply.coverage = {honoured: [], translated: [], ' +
|
|
62
|
+
'flagged: []} naming every declared item exactly once — a dropped ' +
|
|
63
|
+
'handler belongs in `flagged`, never in silence',
|
|
64
|
+
},
|
|
54
65
|
{
|
|
55
66
|
code: 'apply_placeholders_in_output',
|
|
56
67
|
trigger:
|
|
@@ -89,10 +100,122 @@ export function run(state: DeliveryState): StepResult {
|
|
|
89
100
|
return _halt_placeholders(state, violations);
|
|
90
101
|
}
|
|
91
102
|
|
|
103
|
+
const provided = provided_artifact(state.ui_design as Record<string, Any> | null);
|
|
104
|
+
if (provided !== null) {
|
|
105
|
+
const gaps = coverage_gaps(provided, envelope['coverage']);
|
|
106
|
+
if (gaps.length > 0) {
|
|
107
|
+
return _halt_coverage(state, provided, gaps);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
92
111
|
_record_changes(state, envelope);
|
|
93
112
|
return new StepResult({ outcome: Outcome.SUCCESS });
|
|
94
113
|
}
|
|
95
114
|
|
|
115
|
+
/** Buckets the coverage report must sort every declared item into. */
|
|
116
|
+
export const COVERAGE_BUCKETS: ReadonlyArray<string> = ['honoured', 'translated', 'flagged'];
|
|
117
|
+
|
|
118
|
+
/** Declared-item lists a port has to account for, in report order. */
|
|
119
|
+
export const COVERED_INVENTORIES: ReadonlyArray<string> = [
|
|
120
|
+
'interactions',
|
|
121
|
+
'keyframes',
|
|
122
|
+
'assets',
|
|
123
|
+
];
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Return every reason the coverage report fails to account for the artifact.
|
|
127
|
+
*
|
|
128
|
+
* The fidelity ledger the port case never had. `apply` used to validate its
|
|
129
|
+
* output with a single placeholder substring scan and nothing else, so a
|
|
130
|
+
* dropped handler or a lost keyframe left no trace anywhere — the loss was
|
|
131
|
+
* structurally silent, not merely unreported. Requiring each declared item to
|
|
132
|
+
* appear in exactly one bucket turns that silence into a halt: a handler the
|
|
133
|
+
* port could not carry has to be written down in `flagged`.
|
|
134
|
+
*
|
|
135
|
+
* Matching is substring containment against the bucket entries, so an entry
|
|
136
|
+
* may carry its own explanation ("submit handler — translated to a form
|
|
137
|
+
* action") and still count as accounting for `submit handler`.
|
|
138
|
+
*/
|
|
139
|
+
export function coverage_gaps(
|
|
140
|
+
provided: Record<string, Any>,
|
|
141
|
+
coverage: Any,
|
|
142
|
+
): string[] {
|
|
143
|
+
const gaps: string[] = [];
|
|
144
|
+
if (!_isDict(coverage)) {
|
|
145
|
+
return [
|
|
146
|
+
'no `coverage` report in the apply envelope — a provided artifact ' +
|
|
147
|
+
'requires one',
|
|
148
|
+
];
|
|
149
|
+
}
|
|
150
|
+
const entries: string[] = [];
|
|
151
|
+
for (const bucket of COVERAGE_BUCKETS) {
|
|
152
|
+
const value = coverage[bucket];
|
|
153
|
+
if (value === undefined) {
|
|
154
|
+
gaps.push(`\`coverage.${bucket}\` is missing (use an empty list if nothing qualifies)`);
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
if (!Array.isArray(value)) {
|
|
158
|
+
gaps.push(`\`coverage.${bucket}\` must be a list of strings`);
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
for (const item of value) {
|
|
162
|
+
if (typeof item === 'string' && item !== '') {
|
|
163
|
+
entries.push(item.toLowerCase());
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
for (const inventory of COVERED_INVENTORIES) {
|
|
168
|
+
const declared = provided[inventory];
|
|
169
|
+
if (!Array.isArray(declared)) continue;
|
|
170
|
+
for (const item of declared) {
|
|
171
|
+
if (typeof item !== 'string' || item === '') continue;
|
|
172
|
+
const needle = item.toLowerCase();
|
|
173
|
+
if (!entries.some((entry) => entry.includes(needle))) {
|
|
174
|
+
gaps.push(
|
|
175
|
+
`\`${inventory}\`: \`${item}\` appears in no coverage bucket`,
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return gaps;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/** BLOCKED halt — the port did not account for what the artifact declared. */
|
|
184
|
+
function _halt_coverage(
|
|
185
|
+
state: DeliveryState,
|
|
186
|
+
provided: Record<string, Any>,
|
|
187
|
+
gaps: string[],
|
|
188
|
+
): StepResult {
|
|
189
|
+
const directive = _resolve_directive(state);
|
|
190
|
+
const contract = has_design_system(provided)
|
|
191
|
+
? 'A `design-system.json` came with this artifact, so its token values ' +
|
|
192
|
+
'are honoured verbatim — say which, and which you had to translate.'
|
|
193
|
+
: 'No `design-system.json` came with this artifact, so every token ' +
|
|
194
|
+
'value you did not read from it belongs in `translated` or `flagged`.';
|
|
195
|
+
const lines: string[] = [
|
|
196
|
+
agent_directive(directive),
|
|
197
|
+
'> Apply rejected: this is a port of a provided artifact, and the ' +
|
|
198
|
+
'coverage report does not account for it.',
|
|
199
|
+
`> ${contract}`,
|
|
200
|
+
'> Unaccounted:',
|
|
201
|
+
];
|
|
202
|
+
for (const gap of gaps) {
|
|
203
|
+
lines.push(`> - ${gap}`);
|
|
204
|
+
}
|
|
205
|
+
lines.push(
|
|
206
|
+
'> Write `ui_apply.coverage = {honoured: [...], translated: [...], ' +
|
|
207
|
+
'flagged: [...]}` naming every declared interaction, keyframe, and ' +
|
|
208
|
+
'asset exactly once. A handler the port could not carry goes in ' +
|
|
209
|
+
'`flagged` with the reason — never in silence.',
|
|
210
|
+
);
|
|
211
|
+
return new StepResult({
|
|
212
|
+
outcome: Outcome.BLOCKED,
|
|
213
|
+
questions: lines,
|
|
214
|
+
message:
|
|
215
|
+
`UI apply rejected: ${gaps.length} coverage gap(s) against the provided artifact.`,
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
96
219
|
/** Return the agent-written `ui_apply` envelope, or `null`. */
|
|
97
220
|
function _apply_envelope(state: DeliveryState): Record<string, Any> | null {
|
|
98
221
|
const data = _pyTruthy(state.ticket) ? state.ticket : {};
|
|
@@ -132,27 +255,49 @@ function _placeholder_violations_in_output(envelope: Record<string, Any>): strin
|
|
|
132
255
|
function _delegate_to_stack_skill(state: DeliveryState): StepResult {
|
|
133
256
|
const directive = _resolve_directive(state);
|
|
134
257
|
const stack_label = _stack_label(state);
|
|
135
|
-
if (
|
|
258
|
+
if (is_ambiguous_stack(state.stack)) {
|
|
259
|
+
const conflicts = ((state.stack as Record<string, Any>)['ambiguity'] ??
|
|
260
|
+
[]) as ReadonlyArray<string>;
|
|
136
261
|
return new StepResult({
|
|
137
262
|
outcome: Outcome.BLOCKED,
|
|
138
|
-
questions: unsupported_stack_questions('apply'),
|
|
139
|
-
message:
|
|
263
|
+
questions: unsupported_stack_questions('apply', conflicts),
|
|
264
|
+
message:
|
|
265
|
+
`UI apply halted: detection is ambiguous (${conflicts.join('; ')}) — ` +
|
|
266
|
+
'the open question is which project to build for.',
|
|
140
267
|
});
|
|
141
268
|
}
|
|
269
|
+
const provided = provided_artifact(state.ui_design as Record<string, Any> | null);
|
|
270
|
+
const lines: string[] = [
|
|
271
|
+
agent_directive(directive),
|
|
272
|
+
`> Stack: \`${stack_label}\`. Implementing the locked design brief.`,
|
|
273
|
+
bundle_line(state.stack, 'build', stack_label),
|
|
274
|
+
'> Microcopy is locked — every button label, empty-state ' +
|
|
275
|
+
'message, and validation message must come verbatim from ' +
|
|
276
|
+
'`state.ui_design.microcopy`.',
|
|
277
|
+
];
|
|
278
|
+
if (provided !== null) {
|
|
279
|
+
lines.push(
|
|
280
|
+
'> This is a **port**: `state.ui_design.provided_artifact` is the ' +
|
|
281
|
+
'spec. Build it 1:1' +
|
|
282
|
+
(has_design_system(provided)
|
|
283
|
+
? ', and read token values from its `design_system` rather ' +
|
|
284
|
+
'than re-deriving them.'
|
|
285
|
+
: '; no `design_system` came with it, so anything you cannot ' +
|
|
286
|
+
'read from the artifact is a translation you have to name.'),
|
|
287
|
+
'> The envelope must carry `coverage: {honoured, translated, ' +
|
|
288
|
+
'flagged}` accounting for every declared interaction, keyframe, ' +
|
|
289
|
+
'and asset exactly once — apply rejects the envelope otherwise.',
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
lines.push(
|
|
293
|
+
'> 1. Continue — implement the brief and write a ' +
|
|
294
|
+
'`ui_apply` envelope back into state.ticket ' +
|
|
295
|
+
'(rendered: {path: text}, files: [...])',
|
|
296
|
+
'> 2. Abort — drop this UI request',
|
|
297
|
+
);
|
|
142
298
|
return new StepResult({
|
|
143
299
|
outcome: Outcome.BLOCKED,
|
|
144
|
-
questions:
|
|
145
|
-
agent_directive(directive),
|
|
146
|
-
`> Stack: \`${stack_label}\`. Implementing the locked design brief.`,
|
|
147
|
-
bundle_line(stack_label, 'build'),
|
|
148
|
-
'> Microcopy is locked — every button label, empty-state ' +
|
|
149
|
-
'message, and validation message must come verbatim from ' +
|
|
150
|
-
'`state.ui_design.microcopy`.',
|
|
151
|
-
'> 1. Continue — implement the brief and write a ' +
|
|
152
|
-
'`ui_apply` envelope back into state.ticket ' +
|
|
153
|
-
'(rendered: {path: text}, files: [...])',
|
|
154
|
-
'> 2. Abort — drop this UI request',
|
|
155
|
-
],
|
|
300
|
+
questions: lines,
|
|
156
301
|
message: `UI apply pending; delegating to \`${directive}\` for stack \`${stack_label}\`.`,
|
|
157
302
|
});
|
|
158
303
|
}
|
|
@@ -44,6 +44,33 @@ export const PLACEHOLDER_PATTERNS: ReadonlyArray<string> = [
|
|
|
44
44
|
'xxx',
|
|
45
45
|
];
|
|
46
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Optional brief key carrying a user-supplied design artifact.
|
|
49
|
+
*
|
|
50
|
+
* The brief's five required keys are a lossy projection of a finished
|
|
51
|
+
* artifact: `layout` is prose, not a spacing scale, and there is no slot at
|
|
52
|
+
* all for easing, hover behaviour, handlers, or assets. Before this key the
|
|
53
|
+
* pipeline had no channel for a handed-over design, so it rebuilt one from
|
|
54
|
+
* the five-key abstraction and said nothing about the difference. This slot
|
|
55
|
+
* is that channel — one more input to the same step, never a parallel track.
|
|
56
|
+
*/
|
|
57
|
+
export const PROVIDED_ARTIFACT_KEY = 'provided_artifact';
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* What the five-key brief cannot carry from a provided artifact.
|
|
61
|
+
*
|
|
62
|
+
* Stated to the user **before** any regeneration, not discovered afterwards.
|
|
63
|
+
* A supplied `design-system.json` closes the first two; the rest are closed
|
|
64
|
+
* only by the coverage report `apply` demands.
|
|
65
|
+
*/
|
|
66
|
+
export const UNCARRIED_BY_THE_BRIEF: ReadonlyArray<string> = [
|
|
67
|
+
'exact spacing values — `layout` is prose, not a scale',
|
|
68
|
+
'easing curves and animation timing',
|
|
69
|
+
'hover / focus / active behaviour',
|
|
70
|
+
'event handlers and the interactions they drive',
|
|
71
|
+
'the asset manifest (images, icons, fonts the artifact references)',
|
|
72
|
+
];
|
|
73
|
+
|
|
47
74
|
export const AMBIGUITIES: ReadonlyArray<Record<string, string>> = [
|
|
48
75
|
{
|
|
49
76
|
code: 'design_missing',
|
|
@@ -61,6 +88,17 @@ export const AMBIGUITIES: ReadonlyArray<Record<string, string>> = [
|
|
|
61
88
|
'agent re-runs the brief with final strings; ' +
|
|
62
89
|
'halt lists the offending microcopy keys',
|
|
63
90
|
},
|
|
91
|
+
{
|
|
92
|
+
code: 'design_provided_without_contract',
|
|
93
|
+
trigger:
|
|
94
|
+
'state.ui_design.provided_artifact is set but carries no ' +
|
|
95
|
+
'design_system, and the loss has not been acknowledged — the ' +
|
|
96
|
+
'brief would silently regenerate what it cannot carry',
|
|
97
|
+
resolution:
|
|
98
|
+
'user supplies a design-system.json (honoured verbatim), or ' +
|
|
99
|
+
'acknowledges the named losses so the port proceeds with them ' +
|
|
100
|
+
'stated up front',
|
|
101
|
+
},
|
|
64
102
|
{
|
|
65
103
|
code: 'design_unconfirmed',
|
|
66
104
|
trigger: 'brief is well-formed but design_confirmed is unset/False',
|
|
@@ -123,6 +161,11 @@ export function run(state: DeliveryState): StepResult {
|
|
|
123
161
|
return _halt_placeholders(state, placeholders);
|
|
124
162
|
}
|
|
125
163
|
|
|
164
|
+
const provided = provided_artifact(designDict);
|
|
165
|
+
if (provided !== null && !_contract_or_loss_acknowledged(provided)) {
|
|
166
|
+
return _halt_provided_without_contract(state, provided);
|
|
167
|
+
}
|
|
168
|
+
|
|
126
169
|
if (designDict['design_confirmed'] === true) {
|
|
127
170
|
return new StepResult({ outcome: Outcome.SUCCESS });
|
|
128
171
|
}
|
|
@@ -238,6 +281,81 @@ function _walk_placeholders(node: Any, prefix: string, violations: string[]): vo
|
|
|
238
281
|
}
|
|
239
282
|
}
|
|
240
283
|
|
|
284
|
+
/**
|
|
285
|
+
* Return the supplied-artifact envelope, or `null` when none was handed over.
|
|
286
|
+
*
|
|
287
|
+
* Exported because `apply` needs the same answer — the coverage report it
|
|
288
|
+
* demands exists only for a port, and a second copy of "is this a port?"
|
|
289
|
+
* would be the drift this package has paid for before (see the shared
|
|
290
|
+
* `placeholder_paths` walker above).
|
|
291
|
+
*/
|
|
292
|
+
export function provided_artifact(
|
|
293
|
+
design: Record<string, Any> | null | undefined,
|
|
294
|
+
): Record<string, Any> | null {
|
|
295
|
+
if (!_isDict(design)) return null;
|
|
296
|
+
const provided = design[PROVIDED_ARTIFACT_KEY];
|
|
297
|
+
if (!_isDict(provided) || Object.keys(provided).length === 0) return null;
|
|
298
|
+
return provided;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/** True when a machine-readable contract came with the artifact. */
|
|
302
|
+
export function has_design_system(provided: Record<string, Any>): boolean {
|
|
303
|
+
return _isDict(provided['design_system']) && _pyTruthy(provided['design_system']);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/** The port may proceed: either a contract exists, or the losses were stated and accepted. */
|
|
307
|
+
function _contract_or_loss_acknowledged(provided: Record<string, Any>): boolean {
|
|
308
|
+
return has_design_system(provided) || provided['loss_acknowledged'] === true;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* BLOCKED halt — an artifact was handed over with no contract behind it.
|
|
313
|
+
*
|
|
314
|
+
* This is the honest-refusal branch. The pipeline *can* rebuild the artifact
|
|
315
|
+
* from the five-key brief; what it must not do is rebuild it silently. The
|
|
316
|
+
* halt names every value the brief cannot carry, then asks. Answering
|
|
317
|
+
* option 1 sets `loss_acknowledged` and the same losses are on the record.
|
|
318
|
+
*/
|
|
319
|
+
function _halt_provided_without_contract(
|
|
320
|
+
state: DeliveryState,
|
|
321
|
+
provided: Record<string, Any>,
|
|
322
|
+
): StepResult {
|
|
323
|
+
const preview = _preview_input(state);
|
|
324
|
+
const ref = typeof provided['path'] === 'string' && provided['path'] !== ''
|
|
325
|
+
? String(provided['path'])
|
|
326
|
+
: 'the provided artifact';
|
|
327
|
+
const lines: string[] = [
|
|
328
|
+
`> Input: ${preview}`,
|
|
329
|
+
`> \`${ref}\` is a finished design handed over as the spec, and no ` +
|
|
330
|
+
'`design-system.json` came with it. The design brief carries five ' +
|
|
331
|
+
'keys (layout, components, states, microcopy, a11y) — everything ' +
|
|
332
|
+
'below is outside them and would be rebuilt from taste rather than ' +
|
|
333
|
+
'read from your artifact:',
|
|
334
|
+
];
|
|
335
|
+
for (const loss of UNCARRIED_BY_THE_BRIEF) {
|
|
336
|
+
lines.push(`> - ${loss}`);
|
|
337
|
+
}
|
|
338
|
+
lines.push(
|
|
339
|
+
'> 1. Proceed — port it with those five losses on the record; `apply` ' +
|
|
340
|
+
'still has to report what it honoured, translated, and flagged',
|
|
341
|
+
'> 2. Supply a `design-system.json` — its token values are then ' +
|
|
342
|
+
'honoured verbatim instead of re-derived',
|
|
343
|
+
'> 3. Abort — drop this UI request',
|
|
344
|
+
'',
|
|
345
|
+
'**Recommendation: 2 — Supply the contract** — it is the only option ' +
|
|
346
|
+
'that closes the spacing and easing losses at the source. Caveat: ' +
|
|
347
|
+
'pick 1 when no extractor is available; the port then proceeds with ' +
|
|
348
|
+
'the gap stated rather than hidden.',
|
|
349
|
+
);
|
|
350
|
+
return new StepResult({
|
|
351
|
+
outcome: Outcome.BLOCKED,
|
|
352
|
+
questions: lines,
|
|
353
|
+
message:
|
|
354
|
+
'UI design halted: a provided artifact carries no design-system.json; ' +
|
|
355
|
+
`${UNCARRIED_BY_THE_BRIEF.length} value class(es) cannot be carried by the brief.`,
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
|
|
241
359
|
/** Render a one-line preview of the input being designed. */
|
|
242
360
|
function _preview_input(state: DeliveryState): string {
|
|
243
361
|
const data = (_isDict(state.ticket) ? state.ticket : {}) as Record<string, Any>;
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
agent_directive,
|
|
17
17
|
} from '../../delivery_state.js';
|
|
18
18
|
import {
|
|
19
|
-
|
|
19
|
+
is_ambiguous_stack,
|
|
20
20
|
bundle_line,
|
|
21
21
|
unsupported_stack_questions,
|
|
22
22
|
} from './stack_bundles.js';
|
|
@@ -116,6 +116,41 @@ function _pyTruthy(value: Any): boolean {
|
|
|
116
116
|
return true;
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
+
/**
|
|
120
|
+
* Findings the provided artifact already answers — informational, never
|
|
121
|
+
* fix-worthy.
|
|
122
|
+
*
|
|
123
|
+
* A port carries its source's aesthetic on purpose. Left unfiltered, a
|
|
124
|
+
* finding like "cream palette reads as scaffold-default" is indistinguishable
|
|
125
|
+
* from a real defect, so the polish loop spends a round editing the port away
|
|
126
|
+
* from the spec the user approved — the exact regression `daf-slop-vs-provided`
|
|
127
|
+
* witnesses. Marking the finding rather than deleting it keeps it visible in
|
|
128
|
+
* the review output; what changes is that it no longer drives a round.
|
|
129
|
+
*
|
|
130
|
+
* Scope is strict, and the burden sits with the marker: only a decision the
|
|
131
|
+
* artifact **actually covers** may carry the flag. Generative work in the same
|
|
132
|
+
* run is not artifact-covered and stays fully subject to the anti-slop scan.
|
|
133
|
+
*/
|
|
134
|
+
export const ARTIFACT_COVERED_KEY = 'artifact_covered';
|
|
135
|
+
|
|
136
|
+
/** True when this finding is answered by the provided artifact. */
|
|
137
|
+
function _is_artifact_covered(finding: Any): boolean {
|
|
138
|
+
return _isDict(finding) && finding[ARTIFACT_COVERED_KEY] === true;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** Split findings into the ones that drive rounds and the informational rest. */
|
|
142
|
+
export function partition_artifact_covered(findings: ReadonlyArray<Any>): {
|
|
143
|
+
actionable: Any[];
|
|
144
|
+
informational: Any[];
|
|
145
|
+
} {
|
|
146
|
+
const actionable: Any[] = [];
|
|
147
|
+
const informational: Any[] = [];
|
|
148
|
+
for (const finding of findings) {
|
|
149
|
+
(_is_artifact_covered(finding) ? informational : actionable).push(finding);
|
|
150
|
+
}
|
|
151
|
+
return { actionable, informational };
|
|
152
|
+
}
|
|
153
|
+
|
|
119
154
|
/** Apply the polish-loop gate. */
|
|
120
155
|
export function run(state: DeliveryState): StepResult {
|
|
121
156
|
const review = _pyTruthy(state.ui_review) ? (state.ui_review as Record<string, Any>) : {};
|
|
@@ -125,6 +160,11 @@ export function run(state: DeliveryState): StepResult {
|
|
|
125
160
|
}
|
|
126
161
|
const review_clean = _pyTruthy(review['review_clean']);
|
|
127
162
|
|
|
163
|
+
// Artifact-covered findings are dropped from the round-driving set before
|
|
164
|
+
// anything else reads it — including the ceiling check, so a port cannot
|
|
165
|
+
// burn its two rounds on findings it was never allowed to act on.
|
|
166
|
+
findings = partition_artifact_covered(findings as Any[]).actionable;
|
|
167
|
+
|
|
128
168
|
if (review_clean || (findings as Any[]).length === 0) {
|
|
129
169
|
return new StepResult({ outcome: Outcome.SUCCESS });
|
|
130
170
|
}
|
|
@@ -195,12 +235,15 @@ function _delegate_to_polish_skill(
|
|
|
195
235
|
ceiling: number,
|
|
196
236
|
): StepResult {
|
|
197
237
|
const directive = _resolve_directive(state);
|
|
198
|
-
|
|
199
|
-
|
|
238
|
+
if (is_ambiguous_stack(state.stack)) {
|
|
239
|
+
const conflicts = ((state.stack as Record<string, Any>)['ambiguity'] ??
|
|
240
|
+
[]) as ReadonlyArray<string>;
|
|
200
241
|
return new StepResult({
|
|
201
242
|
outcome: Outcome.BLOCKED,
|
|
202
|
-
questions: unsupported_stack_questions('polish'),
|
|
203
|
-
message:
|
|
243
|
+
questions: unsupported_stack_questions('polish', conflicts),
|
|
244
|
+
message:
|
|
245
|
+
`UI polish halted: detection is ambiguous (${conflicts.join('; ')}) — ` +
|
|
246
|
+
'the open question is which project to build for.',
|
|
204
247
|
});
|
|
205
248
|
}
|
|
206
249
|
const stack_label = _stack_label(state);
|
|
@@ -222,7 +265,7 @@ function _delegate_to_polish_skill(
|
|
|
222
265
|
questions: [
|
|
223
266
|
agent_directive(directive),
|
|
224
267
|
`> Stack: \`${stack_label}\`. Polish round ${next_round} of ${ceiling}.`,
|
|
225
|
-
bundle_line(
|
|
268
|
+
bundle_line(state.stack, 'build', stack_label),
|
|
226
269
|
findings_line,
|
|
227
270
|
'> Fix chart-type / contrast findings against the adopted ' +
|
|
228
271
|
"corpus rows (design-intelligence § 'Grounding the " +
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
agent_directive,
|
|
18
18
|
} from '../../delivery_state.js';
|
|
19
19
|
import {
|
|
20
|
-
|
|
20
|
+
is_ambiguous_stack,
|
|
21
21
|
bundle_line,
|
|
22
22
|
unsupported_stack_questions,
|
|
23
23
|
} from './stack_bundles.js';
|
|
@@ -192,11 +192,15 @@ function _stack_label(state: DeliveryState): string {
|
|
|
192
192
|
function _delegate_to_review_skill(state: DeliveryState): StepResult {
|
|
193
193
|
const directive = _resolve_directive(state);
|
|
194
194
|
const stack_label = _stack_label(state);
|
|
195
|
-
if (
|
|
195
|
+
if (is_ambiguous_stack(state.stack)) {
|
|
196
|
+
const conflicts = ((state.stack as Record<string, Any>)['ambiguity'] ??
|
|
197
|
+
[]) as ReadonlyArray<string>;
|
|
196
198
|
return new StepResult({
|
|
197
199
|
outcome: Outcome.BLOCKED,
|
|
198
|
-
questions: unsupported_stack_questions('review'),
|
|
199
|
-
message:
|
|
200
|
+
questions: unsupported_stack_questions('review', conflicts),
|
|
201
|
+
message:
|
|
202
|
+
`UI review halted: detection is ambiguous (${conflicts.join('; ')}) — ` +
|
|
203
|
+
'the open question is which project to build for.',
|
|
200
204
|
});
|
|
201
205
|
}
|
|
202
206
|
return new StepResult({
|
|
@@ -205,7 +209,7 @@ function _delegate_to_review_skill(state: DeliveryState): StepResult {
|
|
|
205
209
|
agent_directive(directive),
|
|
206
210
|
`> Stack: \`${stack_label}\`. Reviewing rendered components ` +
|
|
207
211
|
'against the locked design brief.',
|
|
208
|
-
bundle_line(
|
|
212
|
+
bundle_line(state.stack, 'review', stack_label),
|
|
209
213
|
'> The review pass compares `state.ticket.ui_apply.rendered` ' +
|
|
210
214
|
'against `state.ui_design` (microcopy, states, a11y, layout) ' +
|
|
211
215
|
'and produces a structured `findings` list.',
|