create-agdf 0.14.3 → 0.14.4

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.
Files changed (80) hide show
  1. package/README.md +34 -2
  2. package/generated/.opencode/contracts/interaction.md +2 -2
  3. package/generated/.opencode/skills/agdf-gate-check/SKILL.md +6 -4
  4. package/generated/plugins/agdf/.claude-plugin/plugin.json +1 -1
  5. package/generated/plugins/agdf/.codex-plugin/plugin.json +1 -1
  6. package/generated/plugins/agdf/meta/agdf-plugin.definition.json +1 -1
  7. package/generated/plugins/agdf/meta/contracts/interaction.md +2 -2
  8. package/generated/plugins/agdf/meta/copilot-payload-baseline.json +3 -3
  9. package/generated/plugins/agdf/meta/distribution-profile-history.json +125 -0
  10. package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-plugin.definition.json +1 -1
  11. package/generated/plugins/agdf/runtime/create-agdf/lib/cli/command-registry.js +8 -1
  12. package/generated/plugins/agdf/runtime/create-agdf/lib/cli/parse-args.js +3 -0
  13. package/generated/plugins/agdf/runtime/create-agdf/lib/control-evaluation/doctor.js +13 -0
  14. package/generated/plugins/agdf/runtime/create-agdf/lib/control-evaluation/gate-check.js +64 -13
  15. package/generated/plugins/agdf/runtime/create-agdf/lib/control-evaluation/run-state.js +6 -0
  16. package/generated/plugins/agdf/runtime/create-agdf/lib/control-state/run-identity.js +9 -0
  17. package/generated/plugins/agdf/runtime/create-agdf/lib/control-state/run-state-parser.js +4 -2
  18. package/generated/plugins/agdf/runtime/create-agdf/lib/interaction-presentation.js +57 -7
  19. package/generated/plugins/agdf/runtime/create-agdf/lib/runtime/plugin-provenance.js +46 -3
  20. package/generated/plugins/agdf/runtime/create-agdf/package.json +1 -1
  21. package/generated/plugins/agdf/runtime/runtime-manifest.json +2 -2
  22. package/generated/plugins/agdf/scripts/check-runtime-integrity.mjs +2 -0
  23. package/generated/plugins/agdf/skills/gate-check/SKILL.md +6 -4
  24. package/generated/plugins/agdf/submission/openai/availability.md +1 -1
  25. package/generated/plugins/agdf/submission/openai/capability-matrix.json +1 -1
  26. package/generated/plugins/agdf/submission/openai/release-notes.md +1 -1
  27. package/generated/plugins/agdf/submission/openai/reviewer-cases.json +1 -1
  28. package/generated/plugins/copilot/agdf/.agdf-payload-inventory.json +55 -35
  29. package/generated/plugins/copilot/agdf/copilot-skills/agdf-gate-check/SKILL.md +6 -4
  30. package/generated/plugins/copilot/agdf/copilot-skills/contracts/interaction.md +2 -2
  31. package/generated/plugins/copilot/agdf/meta/agdf-plugin.definition.json +1 -1
  32. package/generated/plugins/copilot/agdf/meta/distribution-profile-history.json +125 -0
  33. package/generated/plugins/copilot/agdf/plugin.json +1 -1
  34. package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-plugin.definition.json +1 -1
  35. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/cli/command-registry.js +8 -1
  36. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/cli/parse-args.js +3 -0
  37. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-evaluation/doctor.js +13 -0
  38. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-evaluation/gate-check.js +64 -13
  39. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-evaluation/run-state.js +6 -0
  40. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-state/run-identity.js +9 -0
  41. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-state/run-state-parser.js +4 -2
  42. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/interaction-presentation.js +57 -7
  43. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/runtime/plugin-provenance.js +46 -3
  44. package/generated/plugins/copilot/agdf/runtime/create-agdf/package.json +1 -1
  45. package/generated/plugins/copilot/agdf/runtime/runtime-manifest.json +2 -2
  46. package/generated/submissions/openai/agdf/.codex-plugin/plugin.json +1 -1
  47. package/generated/submissions/openai/agdf/meta/agdf-plugin.definition.json +1 -1
  48. package/generated/submissions/openai/agdf/meta/contracts/interaction.md +2 -2
  49. package/generated/submissions/openai/agdf/meta/copilot-payload-baseline.json +3 -3
  50. package/generated/submissions/openai/agdf/meta/distribution-profile-history.json +125 -0
  51. package/generated/submissions/openai/agdf/skills/gate-check/SKILL.md +6 -4
  52. package/generated/submissions/openai/agdf/submission/openai/availability.md +1 -1
  53. package/generated/submissions/openai/agdf/submission/openai/capability-matrix.json +1 -1
  54. package/generated/submissions/openai/agdf/submission/openai/inventory.json +16 -12
  55. package/generated/submissions/openai/agdf/submission/openai/listing.json +1 -1
  56. package/generated/submissions/openai/agdf/submission/openai/readiness.json +2 -2
  57. package/generated/submissions/openai/agdf/submission/openai/readiness.md +2 -2
  58. package/generated/submissions/openai/agdf/submission/openai/release-notes.md +1 -1
  59. package/generated/submissions/openai/agdf/submission/openai/reviewer-cases.json +1 -1
  60. package/lib/cli/application.js +24 -6
  61. package/lib/cli/command-registry.js +8 -1
  62. package/lib/cli/parse-args.js +3 -0
  63. package/lib/control-evaluation/doctor.js +13 -0
  64. package/lib/control-evaluation/gate-check.js +64 -13
  65. package/lib/control-evaluation/run-state.js +6 -0
  66. package/lib/control-state/run-identity.js +9 -0
  67. package/lib/control-state/run-state-parser.js +4 -2
  68. package/lib/installers/claude-cache-recovery.js +76 -0
  69. package/lib/installers/copilot-settings.js +146 -16
  70. package/lib/installers/local-marketplace.js +169 -14
  71. package/lib/installers/plugin-installers.js +96 -9
  72. package/lib/interaction-presentation.js +57 -7
  73. package/lib/lifecycle/operations.js +28 -4
  74. package/lib/lifecycle/result.js +4 -4
  75. package/lib/release/profile-history.js +222 -0
  76. package/lib/release/version-bump.js +527 -0
  77. package/lib/release/version-coherence.js +92 -38
  78. package/lib/runtime/distribution-profile-history.js +173 -0
  79. package/lib/runtime/plugin-provenance.js +46 -3
  80. package/package.json +7 -3
@@ -0,0 +1,125 @@
1
+ {
2
+ "schema_version": 1,
3
+ "contracts": {
4
+ "five-profile-v1": {
5
+ "distribution_profiles": {
6
+ "schemaVersion": 1,
7
+ "marketplaceIdentities": {
8
+ "durable": "agdf",
9
+ "generatedRepository": "agdf-repo"
10
+ },
11
+ "profiles": {
12
+ "source-development": {
13
+ "runtime": "absent",
14
+ "installable": false,
15
+ "machineValidation": "unavailable"
16
+ },
17
+ "runtime-plugin": {
18
+ "runtime": "required",
19
+ "installable": true,
20
+ "machineValidation": "local_exact_version_digest"
21
+ },
22
+ "copilot-runtime-plugin": {
23
+ "runtime": "required",
24
+ "installable": true,
25
+ "machineValidation": "local_exact_version_digest_inventory"
26
+ },
27
+ "opencode-config-local": {
28
+ "runtime": "config_local_package",
29
+ "installable": true,
30
+ "machineValidation": "local_exact_version"
31
+ },
32
+ "portable-skills": {
33
+ "runtime": "absent",
34
+ "installable": true,
35
+ "machineValidation": "unavailable_or_external_required"
36
+ }
37
+ }
38
+ },
39
+ "contract_digest": "0211f4e6054a23f0a3ba302e57303adcb8f5903581e99643f803647dd156fe32"
40
+ },
41
+ "four-profile-v1": {
42
+ "distribution_profiles": {
43
+ "schemaVersion": 1,
44
+ "marketplaceIdentities": {
45
+ "durable": "agdf",
46
+ "generatedRepository": "agdf-repo"
47
+ },
48
+ "profiles": {
49
+ "source-development": {
50
+ "runtime": "absent",
51
+ "installable": false,
52
+ "machineValidation": "unavailable"
53
+ },
54
+ "runtime-plugin": {
55
+ "runtime": "required",
56
+ "installable": true,
57
+ "machineValidation": "local_exact_version_digest"
58
+ },
59
+ "opencode-config-local": {
60
+ "runtime": "config_local_package",
61
+ "installable": true,
62
+ "machineValidation": "local_exact_version"
63
+ },
64
+ "portable-skills": {
65
+ "runtime": "absent",
66
+ "installable": true,
67
+ "machineValidation": "unavailable_or_external_required"
68
+ }
69
+ }
70
+ },
71
+ "contract_digest": "9987baa4ea91e28a096cac2be8daa876f1c0593e7edbfe2e96b713814aa65ce8"
72
+ }
73
+ },
74
+ "releases": {
75
+ "0.13.6": {
76
+ "contract_id": "four-profile-v1",
77
+ "provenance_schema_version": 1,
78
+ "profile_id": "runtime-plugin",
79
+ "entry_digest": "1c21c3fa99cdd788994013f25cbe606ffdcea2cc91d53c679cf061567f652bf3",
80
+ "status": "supported"
81
+ },
82
+ "0.13.7": {
83
+ "contract_id": "four-profile-v1",
84
+ "provenance_schema_version": 1,
85
+ "profile_id": "runtime-plugin",
86
+ "entry_digest": "6d5383537d2640dc13773f2929dd94d0e7e219e82d08418464c77786b475c3ee",
87
+ "status": "supported"
88
+ },
89
+ "0.13.8": {
90
+ "contract_id": "four-profile-v1",
91
+ "provenance_schema_version": 1,
92
+ "profile_id": "runtime-plugin",
93
+ "entry_digest": "405e8cfa72ec2e469354dab52197675783b3723adb969a0692e56ba7c95c85c8",
94
+ "status": "supported"
95
+ },
96
+ "0.14.1": {
97
+ "contract_id": "four-profile-v1",
98
+ "provenance_schema_version": 1,
99
+ "profile_id": "runtime-plugin",
100
+ "entry_digest": "1a6fd6f6a411eddb29e82d7b7abc7d5f658312f555dcf39e160a709194a8b867",
101
+ "status": "supported"
102
+ },
103
+ "0.14.2": {
104
+ "contract_id": "five-profile-v1",
105
+ "provenance_schema_version": 1,
106
+ "profile_id": "runtime-plugin",
107
+ "entry_digest": "f71ee26df3d4a89ecc727a1c30b40221cf062fce9f716a83453bced9503be8fd",
108
+ "status": "supported"
109
+ },
110
+ "0.14.3": {
111
+ "contract_id": "five-profile-v1",
112
+ "provenance_schema_version": 1,
113
+ "profile_id": "runtime-plugin",
114
+ "entry_digest": "c5dbe4044d11a976cd4ccd6de6cf1405ebfcb4a26ce5c6308c34f10142db50c9",
115
+ "status": "supported"
116
+ },
117
+ "0.14.4": {
118
+ "contract_id": "five-profile-v1",
119
+ "provenance_schema_version": 1,
120
+ "profile_id": "runtime-plugin",
121
+ "entry_digest": "a441d633fe11ea402c3366cfac0cec659d32eae5eb4ae6b1d25a1e366a029813",
122
+ "status": "supported"
123
+ }
124
+ }
125
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agdf",
3
- "version": "0.14.3",
3
+ "version": "0.14.4",
4
4
  "description": "Control layer for governed AI-assisted delivery.",
5
5
  "author": {
6
6
  "name": "Arndt Gold",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "id": "agdf",
4
- "version": "0.14.3",
4
+ "version": "0.14.4",
5
5
  "displayName": "AI Governance & Delivery Framework",
6
6
  "developerName": "Arndt Gold",
7
7
  "description": "Control layer for governed AI-assisted delivery.",
@@ -18,7 +18,7 @@ export const commandRegistry = Object.freeze([
18
18
  command("opencode-status", { preferred: [""], scaffold: [""] }),
19
19
  command("status", { preferred: [" [--surface <surface>] [--run <run_id>] [--json]"] }),
20
20
  command("runtime-checks", { preferred: [" <status|enable|manual> --surface <codex|claude|copilot|opencode> [--json]"] }),
21
- command("disable", { preferred: [" --surface <surface> [--scope repository] [--dir <path>]"] }),
21
+ command("disable", { preferred: [" --surface <surface> [--scope repository] [--shared] [--dir <path>]"] }),
22
22
  command("uninstall", { preferred: [" --surface <surface> --scope global [--confirm]"] }),
23
23
  command("opencode-repo", { preferred: [""], scaffold: [""] }),
24
24
  command("init", { preferred: [""], scaffold: [""] }),
@@ -65,6 +65,12 @@ export function validateCommandOptions(options) {
65
65
  throw new Error("uninstall requires explicit --scope global");
66
66
  }
67
67
  if (options.confirm && options.target !== "uninstall") throw new Error("--confirm is supported only by uninstall");
68
+ if (options.shared && !(options.target === "disable" && options.surface === "copilot" && options.scope === "repository")) {
69
+ throw new Error("--shared is supported only by disable --surface copilot --scope repository");
70
+ }
71
+ if (options.target === "disable" && options.surface === "copilot" && options.scope !== "repository") {
72
+ throw new Error("Copilot disable requires explicit --scope repository");
73
+ }
68
74
  if (options.runtimeChecksDecision && !["codex", "claude", "copilot", "opencode"].includes(options.target)) {
69
75
  throw new Error("--runtime-checks is supported only by codex, claude, copilot and opencode installation commands");
70
76
  }
@@ -126,6 +132,7 @@ Options:
126
132
  --scope <repository|global>
127
133
  Select the lifecycle mutation scope
128
134
  --confirm Apply a previously previewed global uninstall plan
135
+ --shared Apply Copilot repository disable through shared .github/copilot/settings.json
129
136
  --runtime-checks <enable|manual|cancel>
130
137
  Make the installation-time automatic-check decision explicitly; no TTY defaults to manual
131
138
  --fixture <path>
@@ -45,6 +45,7 @@ export function parseArgs(argv, dependencies = {}) {
45
45
  let allActive = false;
46
46
  let scope;
47
47
  let confirm = false;
48
+ let shared = false;
48
49
  let runtimeChecksDecision;
49
50
  let runtimeChecksAction;
50
51
 
@@ -61,6 +62,7 @@ export function parseArgs(argv, dependencies = {}) {
61
62
  if (arg === "--generate-candidates") { generateCandidates = true; continue; }
62
63
  if (arg === "--all-active") { allActive = true; continue; }
63
64
  if (arg === "--confirm") { confirm = true; continue; }
65
+ if (arg === "--shared") { shared = true; continue; }
64
66
 
65
67
  if (arg === "--runtime-checks") {
66
68
  const next = requiredValue(args, i, arg);
@@ -162,6 +164,7 @@ export function parseArgs(argv, dependencies = {}) {
162
164
  allActive,
163
165
  scope,
164
166
  confirm,
167
+ shared,
165
168
  runtimeChecksDecision,
166
169
  runtimeChecksAction: runtimeChecksAction ?? "status",
167
170
  generatorModel,
@@ -130,6 +130,19 @@ export function evaluateDoctor(targetDir, selection = {}) {
130
130
  "Add at least one evidence row or explicitly document that no evidence exists yet.",
131
131
  );
132
132
  }
133
+
134
+ for (const identityFinding of selectedRunState.identity_findings ?? []) {
135
+ addFinding(
136
+ findings,
137
+ "revise",
138
+ identityFinding.code,
139
+ identityFinding.code === "AGDF_RUN_ID_INVALID"
140
+ ? "The selected run state has a missing or invalid run_id; interaction cards cannot be rendered for it."
141
+ : "The selected run state has a missing or invalid revision_id; approval interactions cannot be rendered for it.",
142
+ runPath,
143
+ "Run run-migrate to repair the run identity, or migrate the legacy state to a canonical run record.",
144
+ );
145
+ }
133
146
  }
134
147
 
135
148
  const backlogPath = join(".agdf", "control", "MASTER_BACKLOG.md");
@@ -1,4 +1,4 @@
1
- import { attachApprovalOrientationSnapshot, buildArtefactRefs, buildQualityReadiness, gateTitle, localePack, renderApprovalOrientationSnapshot, renderOperationalStatusCard, resolveHumanRunTitle } from '../interaction-presentation.js';
1
+ import { attachApprovalOrientationSnapshot, buildArtefactRefs, buildQualityReadiness, gateTitle, localePack, renderApprovalOrientationSnapshot, renderOperationalStatusCard, resolveHumanRunTitle, validateApprovalOrientationPreconditions, validateApprovalOrientationSnapshot, validateOperationalStatusCardPreconditions } from '../interaction-presentation.js';
2
2
  import { interactionLocales, resolveConfiguredChatLanguage } from '../cli/runtime-context.js';
3
3
  import { evaluateDoctor } from './doctor.js';
4
4
  import { analyzeDeliveryMap, deriveQualityOutlook } from './delivery-map.js';
@@ -300,8 +300,9 @@ export function evaluateGateCheck(targetDir, selection = {}) {
300
300
  humanPresentation,
301
301
  revisionId,
302
302
  });
303
+ const readyForApproval = isReadyUserGateApproval({ status, currentGate, missingApproval });
303
304
  const approvalOrientation = attachApprovalOrientationSnapshot(statusCard, {
304
- ready: isReadyUserGateApproval({ status, currentGate, missingApproval }),
305
+ ready: readyForApproval,
305
306
  humanPresentation,
306
307
  revisionId,
307
308
  registry: interactionLocales,
@@ -312,6 +313,50 @@ export function evaluateGateCheck(targetDir, selection = {}) {
312
313
  enumerable: false,
313
314
  });
314
315
 
316
+ const approvalPresentation = renderApprovalOrientationSnapshot(approvalOrientation, {
317
+ registry: interactionLocales,
318
+ expectedIdentity: {
319
+ run_id: statusCard.run_id,
320
+ revision_id: revisionId,
321
+ current_gate: currentGate,
322
+ presentation_language: statusCard.presentation_language,
323
+ },
324
+ });
325
+ const presentationDiagnostics = {};
326
+ if (!statusPresentation) {
327
+ presentationDiagnostics.status_presentation_errors = [
328
+ ...validateOperationalStatusCardPreconditions(statusCard, {
329
+ registry: interactionLocales,
330
+ humanPresentation,
331
+ }).errors,
332
+ ];
333
+ }
334
+ if (readyForApproval && !approvalPresentation) {
335
+ presentationDiagnostics.approval_presentation_errors = approvalOrientation
336
+ ? [
337
+ ...validateApprovalOrientationSnapshot(approvalOrientation, {
338
+ registry: interactionLocales,
339
+ expectedIdentity: {
340
+ run_id: statusCard.run_id,
341
+ revision_id: revisionId,
342
+ current_gate: currentGate,
343
+ presentation_language: statusCard.presentation_language,
344
+ },
345
+ }).errors,
346
+ ]
347
+ : [
348
+ ...validateApprovalOrientationPreconditions({
349
+ statusCard,
350
+ humanPresentation,
351
+ registry: interactionLocales,
352
+ requestedLocale: presentationLocale,
353
+ }).errors,
354
+ ];
355
+ if (!presentationDiagnostics.approval_presentation_errors.length) {
356
+ presentationDiagnostics.approval_presentation_errors = ["snapshot_unavailable"];
357
+ }
358
+ }
359
+
315
360
  return {
316
361
  schema_version: "1",
317
362
  status,
@@ -332,15 +377,8 @@ export function evaluateGateCheck(targetDir, selection = {}) {
332
377
  candidate_runs: runState.candidate_runs ?? [],
333
378
  status_card: statusCard,
334
379
  status_presentation: statusPresentation,
335
- approval_presentation: renderApprovalOrientationSnapshot(approvalOrientation, {
336
- registry: interactionLocales,
337
- expectedIdentity: {
338
- run_id: statusCard.run_id,
339
- revision_id: revisionId,
340
- current_gate: currentGate,
341
- presentation_language: statusCard.presentation_language,
342
- },
343
- }),
380
+ approval_presentation: approvalPresentation,
381
+ ...(Object.keys(presentationDiagnostics).length ? { presentation_diagnostics: presentationDiagnostics } : {}),
344
382
  delivery_map: {
345
383
  relationships: deliveryMap.relationships,
346
384
  mode_slice_decision: runState.mode_slice_decision,
@@ -368,6 +406,14 @@ export function printApprovalEnvelope(report, { io = console, reEvaluate } = {})
368
406
  if (report?.approval_presentation) {
369
407
  io.log(report.approval_presentation.blocks.run_status_card.markdown);
370
408
  io.log("");
409
+ if (report.status_presentation?.markdown) {
410
+ io.log(report.status_presentation.markdown);
411
+ } else {
412
+ const pack = localePack(interactionLocales, report.approval_presentation.presentation_language || "en");
413
+ const codes = report.presentation_diagnostics?.status_presentation_errors ?? [];
414
+ io.log(codes.length ? `${pack.interaction.statusPresentationFailure} (${codes.join(", ")})` : pack.interaction.statusPresentationFailure);
415
+ }
416
+ io.log("");
371
417
  io.log(report.approval_presentation.blocks.gate_transition_card.markdown);
372
418
  io.log("");
373
419
  io.log(report.approval_presentation.approval_interaction.exact_text_fallback);
@@ -386,7 +432,10 @@ export function printApprovalEnvelope(report, { io = console, reEvaluate } = {})
386
432
  const pack = localePack(interactionLocales, refreshed?.status_card?.presentation_language || report?.status_card?.presentation_language || "en");
387
433
  const refreshedApproval = canonicalApprovalForReport(refreshed);
388
434
  if (initialApproval && refreshedApproval) {
389
- io.log(pack.interaction.presentationFailure);
435
+ const codes = refreshed?.presentation_diagnostics?.approval_presentation_errors
436
+ ?? report?.presentation_diagnostics?.approval_presentation_errors
437
+ ?? [];
438
+ io.log(codes.length ? `${pack.interaction.presentationFailure} (${codes.join(", ")})` : pack.interaction.presentationFailure);
390
439
  io.log(pack.interaction.exactTextRequest.replace("{approval}", refreshedApproval));
391
440
  return Object.freeze({ outcome: "exact_text_recovery", requested_decision: true, status: refreshed.status });
392
441
  }
@@ -404,7 +453,9 @@ export function printApprovalEnvelope(report, { io = console, reEvaluate } = {})
404
453
  function printGateCheckStatusCard(report, io) {
405
454
  const card = report.status_card;
406
455
  if (!report.status_presentation?.markdown) {
407
- io.log(localePack(interactionLocales, card?.presentation_language || "en").interaction.statusPresentationFailure);
456
+ const failure = localePack(interactionLocales, card?.presentation_language || "en").interaction.statusPresentationFailure;
457
+ const codes = report.presentation_diagnostics?.status_presentation_errors ?? [];
458
+ io.log(codes.length ? `${failure} (${codes.join(", ")})` : failure);
408
459
  return false;
409
460
  }
410
461
  io.log(report.status_presentation.markdown);
@@ -2,6 +2,7 @@ import { existsSync, readFileSync, realpathSync, statSync } from "node:fs";
2
2
  import { isAbsolute, join, relative, resolve } from "node:path";
3
3
  import process from "node:process";
4
4
  import { parseControlState, resolveRuns } from "../control-state/index.js";
5
+ import { validateRunIdentity } from "../control-state/run-identity.js";
5
6
  import { buildRunCandidates } from "../interaction-presentation.js";
6
7
  import { cleanStatusCell, filled, isPlaceholderValue, readTargetFile } from "./shared.js";
7
8
  import { extractField, isSafeRepoRelativePath, readVerifiedChangeRecord } from "./verified-change.js";
@@ -87,6 +88,7 @@ export function readRunState(targetDir, selection = {}) {
87
88
  memory: {},
88
89
  candidate_runs: candidateRuns,
89
90
  resolution_error: resolutionError,
91
+ identity_findings: [],
90
92
  };
91
93
  }
92
94
 
@@ -101,6 +103,10 @@ export function readRunState(targetDir, selection = {}) {
101
103
  path: runPath,
102
104
  content,
103
105
  ...parsed,
106
+ identity_findings: validateRunIdentity({
107
+ runId: extractField(content, "run_id").replace(/^`|`$/g, ""),
108
+ revisionId: extractField(content, "revision_id").replace(/^`|`$/g, ""),
109
+ }),
104
110
  };
105
111
  }
106
112
 
@@ -0,0 +1,9 @@
1
+ export const RUN_ID_PATTERN = /^[a-z0-9][a-z0-9._-]{0,127}$/;
2
+ export const REVISION_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
3
+
4
+ export function validateRunIdentity({ runId, revisionId } = {}) {
5
+ const findings = [];
6
+ if (!RUN_ID_PATTERN.test(String(runId ?? ""))) findings.push({ code: "AGDF_RUN_ID_INVALID" });
7
+ if (!REVISION_ID_PATTERN.test(String(revisionId ?? ""))) findings.push({ code: "AGDF_RUN_REVISION_ID_INVALID" });
8
+ return findings;
9
+ }
@@ -1,4 +1,6 @@
1
- export const RUN_ID_PATTERN = /^[a-z0-9][a-z0-9._-]{0,127}$/;
1
+ import { REVISION_ID_PATTERN, RUN_ID_PATTERN } from "./run-identity.js";
2
+
3
+ export { RUN_ID_PATTERN } from "./run-identity.js";
2
4
  export const LIFECYCLES = new Set([
3
5
  "active",
4
6
  "completed",
@@ -34,7 +36,7 @@ export function parseRunState(content, expected) {
34
36
  findings.push({ code: "AGDF_RUN_LIFECYCLE_INVALID" });
35
37
  if (!/^[1-9]\d*$/.test(values.get("revision") ?? ""))
36
38
  findings.push({ code: "AGDF_RUN_REVISION_INVALID" });
37
- if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(values.get("revision_id") ?? ""))
39
+ if (!REVISION_ID_PATTERN.test(values.get("revision_id") ?? ""))
38
40
  findings.push({ code: "AGDF_RUN_REVISION_ID_INVALID" });
39
41
  return {
40
42
  content,
@@ -1,3 +1,5 @@
1
+ import { RUN_ID_PATTERN } from "./control-state/run-identity.js";
2
+
1
3
  const REQUIRED_GATES = ["UR", "PRD", "SD", "TP", "QA", "UAT"];
2
4
  const ARTEFACT_ORDER = ["UR", "PRD", "SD", "TP"];
3
5
  const OUTCOMES = new Set(["approve", "revise", "decline", "cancel", "no_response", "timeout", "empty", "invalid", "stale"]);
@@ -313,17 +315,37 @@ function operationalBreadcrumb(value, labels) {
313
315
  .join(labels.breadcrumbSeparator);
314
316
  }
315
317
 
318
+ export function validateOperationalStatusCardPreconditions(statusCard, {
319
+ registry,
320
+ humanPresentation,
321
+ } = {}) {
322
+ const errors = [];
323
+ if (!plainObject(statusCard)) errors.push("status_card_missing");
324
+ if (humanPresentation !== undefined && !plainObject(humanPresentation)) errors.push("human_presentation_missing");
325
+ if (plainObject(statusCard)) {
326
+ if (!String(statusCard.run_id ?? "").trim()) errors.push("run_id_missing");
327
+ if (!String(statusCard.current_gate ?? "").trim()) errors.push("current_gate_missing");
328
+ let locale = "";
329
+ try {
330
+ locale = resolvePresentationLocale(registry, statusCard.presentation_language);
331
+ } catch {
332
+ locale = "";
333
+ }
334
+ if (!locale) errors.push("locale_unresolved");
335
+ }
336
+ return Object.freeze({ valid: errors.length === 0, errors: Object.freeze(errors) });
337
+ }
338
+
316
339
  export function renderOperationalStatusCard(statusCard, {
317
340
  registry,
318
341
  humanPresentation,
319
342
  revisionId = "",
320
343
  } = {}) {
321
- if (!plainObject(statusCard) || !plainObject(humanPresentation)) return null;
344
+ if (!validateOperationalStatusCardPreconditions(statusCard, { registry, humanPresentation: humanPresentation ?? null }).valid) return null;
322
345
  const runId = String(statusCard.run_id ?? "").trim();
323
346
  const currentGate = String(statusCard.current_gate ?? "").trim();
324
347
  const revision = String(revisionId ?? "").trim() || "unversioned";
325
348
  const locale = resolvePresentationLocale(registry, statusCard.presentation_language);
326
- if (!runId || !currentGate || !locale) return null;
327
349
 
328
350
  const pack = localePack(registry, locale);
329
351
  const labels = pack.statusCard;
@@ -537,6 +559,37 @@ export function normalizeInteractionOutcome(value, { expectedApproval, stale = f
537
559
  return "invalid";
538
560
  }
539
561
 
562
+ export function validateApprovalOrientationPreconditions({
563
+ statusCard,
564
+ humanPresentation,
565
+ registry,
566
+ requestedLocale,
567
+ } = {}) {
568
+ const errors = [];
569
+ if (!plainObject(statusCard)) return Object.freeze({ valid: false, errors: Object.freeze(["status_card_missing"]) });
570
+ if (humanPresentation !== undefined && !plainObject(humanPresentation)) errors.push("human_presentation_missing");
571
+ const gate = String(statusCard.current_gate ?? "").trim();
572
+ const runId = String(statusCard.run_id ?? "").trim();
573
+ if (!REQUIRED_GATES.includes(gate)) errors.push("gate_not_user_gate");
574
+ if (!RUN_ID_PATTERN.test(runId)) errors.push("run_id_invalid");
575
+ if (statusCard.status !== "open") errors.push("status_not_open");
576
+ if (statusCard.missing_approval !== `Approval: ${gate}`) errors.push("missing_approval_mismatch");
577
+ const nextGate = String(statusCard.next_gate_after_approval ?? "none");
578
+ const nextUserGate = String(statusCard.next_user_gate ?? "").trim();
579
+ const userActionRequired = String(statusCard.user_action_required ?? "").trim();
580
+ const userActionSemanticsValid = (userActionRequired === "no" && nextUserGate === "none")
581
+ || (userActionRequired === "yes" && REQUIRED_GATES.includes(nextUserGate) && nextGate === nextUserGate);
582
+ if (!userActionSemanticsValid) errors.push("user_action_semantics_invalid");
583
+ let locale = "";
584
+ try {
585
+ locale = resolvePresentationLocale(registry, requestedLocale);
586
+ } catch {
587
+ locale = "";
588
+ }
589
+ if (!locale) errors.push("locale_unresolved");
590
+ return Object.freeze({ valid: errors.length === 0, errors: Object.freeze(errors) });
591
+ }
592
+
540
593
  export function buildApprovalOrientationSnapshot({
541
594
  ready = false,
542
595
  statusCard,
@@ -545,11 +598,11 @@ export function buildApprovalOrientationSnapshot({
545
598
  registry,
546
599
  requestedLocale,
547
600
  } = {}) {
548
- if (!ready || !plainObject(statusCard) || !plainObject(humanPresentation)) return null;
601
+ if (!ready) return null;
602
+ if (!validateApprovalOrientationPreconditions({ statusCard, humanPresentation: humanPresentation ?? null, registry, requestedLocale }).valid) return null;
549
603
  const gate = String(statusCard.current_gate ?? "").trim();
550
604
  const runId = String(statusCard.run_id ?? "").trim();
551
605
  const expectedApproval = `Approval: ${gate}`;
552
- if (!REQUIRED_GATES.includes(gate) || !/^[A-Za-z0-9._-]+$/.test(runId) || statusCard.status !== "open" || statusCard.missing_approval !== expectedApproval) return null;
553
606
 
554
607
  const locale = resolvePresentationLocale(registry, requestedLocale);
555
608
  const pack = localePack(registry, locale);
@@ -560,9 +613,6 @@ export function buildApprovalOrientationSnapshot({
560
613
  const nextGate = String(statusCard.next_gate_after_approval ?? "none");
561
614
  const nextUserGate = String(statusCard.next_user_gate ?? "").trim();
562
615
  const userActionRequired = String(statusCard.user_action_required ?? "").trim();
563
- const userActionSemanticsValid = (userActionRequired === "no" && nextUserGate === "none")
564
- || (userActionRequired === "yes" && REQUIRED_GATES.includes(nextUserGate) && nextGate === nextUserGate);
565
- if (!userActionSemanticsValid) return null;
566
616
  const narration = pack.primary.narration.gates[gate] ?? {};
567
617
  const nextDecision = userActionRequired === "no"
568
618
  ? pack.primary.narration.noAction
@@ -137,6 +137,22 @@ export function validateDistributionProfiles(definition) {
137
137
  return { status: "matched", contract };
138
138
  }
139
139
 
140
+ function classifyInstalledHistoricalProfile(catalogue, definition, classifyHistoricalProfile) {
141
+ if (typeof classifyHistoricalProfile !== "function") {
142
+ return { status: "invalid", reason: "profile_history_invalid" };
143
+ }
144
+ const result = classifyHistoricalProfile({
145
+ catalogue,
146
+ version: definition?.version,
147
+ distributionProfiles: definition?.distributionProfiles,
148
+ });
149
+ if (result.status !== "matched") return result;
150
+ return {
151
+ ...result,
152
+ contract: catalogue.contracts[result.contract_id].distribution_profiles,
153
+ };
154
+ }
155
+
140
156
  export function inspectGeneratedRepositoryMarketplace(targetDir) {
141
157
  const marketplacePath = join(targetDir, ".agents", "plugins", "marketplace.json");
142
158
  if (!existsSync(marketplacePath)) return { status: "absent", marketplacePath };
@@ -196,11 +212,23 @@ export function inspectInstallationProvenance(pluginRoot, {
196
212
  allowLegacy = false,
197
213
  profileId = "runtime-plugin",
198
214
  inventoryDigest = null,
215
+ allowHistoricalProfilesForMigration = false,
216
+ distributionProfileHistory = null,
217
+ classifyHistoricalProfile = null,
199
218
  } = {}) {
200
219
  const markerPath = join(pluginRoot, INSTALLATION_PROVENANCE_FILE);
201
220
  const legacyPath = join(pluginRoot, LEGACY_LOCAL_INSTALL_FILE);
202
221
  if (!existsSync(markerPath)) {
203
222
  if (allowLegacy && existsSync(legacyPath)) {
223
+ const currentProfile = validateDistributionProfiles(definition);
224
+ if (Object.hasOwn(definition ?? {}, "distributionProfiles")
225
+ && currentProfile.status !== "matched") {
226
+ return allowHistoricalProfilesForMigration
227
+ ? classifyInstalledHistoricalProfile(distributionProfileHistory, definition, classifyHistoricalProfile).status === "matched"
228
+ ? { status: "invalid", reason: "installation_provenance_invalid" }
229
+ : classifyInstalledHistoricalProfile(distributionProfileHistory, definition, classifyHistoricalProfile)
230
+ : currentProfile;
231
+ }
204
232
  const marker = readJson(legacyPath);
205
233
  if (!marker
206
234
  || marker.schema_version !== 1
@@ -223,8 +251,14 @@ export function inspectInstallationProvenance(pluginRoot, {
223
251
  if (profile.status !== "matched") return profile;
224
252
  return { status: "missing", reason: "installation_provenance_missing" };
225
253
  }
226
- const profile = validateDistributionProfiles(definition);
227
- if (profile.status !== "matched") return profile;
254
+ const currentProfile = validateDistributionProfiles(definition);
255
+ const historicalProfile = currentProfile.status !== "matched" && allowHistoricalProfilesForMigration
256
+ ? classifyInstalledHistoricalProfile(distributionProfileHistory, definition, classifyHistoricalProfile)
257
+ : null;
258
+ if (currentProfile.status !== "matched" && historicalProfile?.status !== "matched") {
259
+ return historicalProfile ?? currentProfile;
260
+ }
261
+ const profile = currentProfile.status === "matched" ? currentProfile : historicalProfile;
228
262
  const marker = readJson(markerPath);
229
263
  if (!marker
230
264
  || marker.schema_version !== 1
@@ -247,7 +281,16 @@ export function inspectInstallationProvenance(pluginRoot, {
247
281
  if (observedSourceDigest !== marker.source_digest) {
248
282
  return { status: "invalid", reason: "source_digest_mismatch", marker, observedSourceDigest };
249
283
  }
250
- return { status: "matched", marker, observedSourceDigest };
284
+ return {
285
+ status: "matched",
286
+ marker,
287
+ observedSourceDigest,
288
+ profileClassification: historicalProfile ? "supported_historical" : "current",
289
+ historicalReleaseVersion: historicalProfile?.release_version ?? null,
290
+ historicalContractId: historicalProfile?.contract_id ?? null,
291
+ historicalContractDigest: historicalProfile?.contract_digest ?? null,
292
+ historicalEntryDigest: historicalProfile?.entry_digest ?? null,
293
+ };
251
294
  }
252
295
 
253
296
  export const distributionProfileContract = Object.freeze({
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agdf/local-validator-runtime",
3
- "version": "0.14.3",
3
+ "version": "0.14.4",
4
4
  "private": true,
5
5
  "type": "module"
6
6
  }
@@ -2,7 +2,7 @@
2
2
  "schema_version": "1",
3
3
  "generated": true,
4
4
  "source": "create-agdf/cli",
5
- "version": "0.14.3",
5
+ "version": "0.14.4",
6
6
  "entrypoint": "create-agdf/bin/agdf-validator.js",
7
- "digest": "8f6dbd5e647aff7dfc1405f4e54a5b135a8d820858b5f8f85873964f6eb2f7cf"
7
+ "digest": "68b83a6721a799c34067cdbcc0ed6664f7fbf89bce186a3d8de284b0959deac7"
8
8
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agdf",
3
- "version": "0.14.3",
3
+ "version": "0.14.4",
4
4
  "description": "Control layer for governed AI-assisted delivery.",
5
5
  "author": {
6
6
  "name": "Arndt Gold",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "id": "agdf",
4
- "version": "0.14.3",
4
+ "version": "0.14.4",
5
5
  "displayName": "AI Governance & Delivery Framework",
6
6
  "developerName": "Arndt Gold",
7
7
  "description": "Control layer for governed AI-assisted delivery.",
@@ -154,8 +154,8 @@ required decision and one neutral instruction to choose approve, request revisio
154
154
  or decline. It does not contain the exact approval value or quality outlook. It uses localized human-readable labels
155
155
  and must not contain evidence, diagnostic codes, raw control-state keys,
156
156
  allowed/forbidden inventories or machine values. The complete Run Status Card remains the operational,
157
- CLI and audit projection and remains available for complete detail outside the
158
- approval-time compact view.
157
+ CLI and audit projection. Every ready-gate presentation renders the complete operational Run Status Card exactly once, between the compact approval-time Run Status Card and the Gate Transition Card, consumed verbatim from the code-owned status presentation; when it is undeliverable, the localized status-presentation failure line with its concrete diagnostic codes takes its place and the decision is still requested.
158
+ The exact-approval once-only requirement applies to the compact approval-time Run Status Card and the Gate Transition Card only; the complete Run Status Card may carry the missing approval as audit data.
159
159
 
160
160
  The first scan across both cards reveals the requested decision, readiness,
161
161
  required approval, approval effect, remaining boundary and next transition.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schema_version": 1,
3
3
  "profile_id": "copilot-runtime-plugin",
4
- "max_files": 78,
5
- "max_bytes": 550979,
6
- "rationale": "Reviewed Copilot-only manifest, ten prefixed skills, required contracts, exact-version runtime, Delivery Path Search input-integrity provenance and evidence-plane separation. Any further increase requires review."
4
+ "max_files": 80,
5
+ "max_bytes": 568459,
6
+ "rationale": "Reviewed Copilot-only manifest, ten prefixed skills, required contracts, exact-version runtime, Delivery Path Search input-integrity provenance, evidence-plane separation, shared run-identity validation and the one-file distribution profile history catalogue. Measured payload is 80 files/563615 bytes; no byte-capacity increase was required. Any further increase requires review."
7
7
  }