@aifabrix/builder 2.60.0 → 2.61.2

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 (112) hide show
  1. package/README.md +14 -11
  2. package/docs/README.md +80 -0
  3. package/docs/builder-help/evidence-patterns.json +155 -0
  4. package/docs/builder-help/golden-examples/crm-company.json +30 -0
  5. package/docs/builder-help/golden-examples/crm-deal.json +29 -0
  6. package/docs/builder-help/golden-examples/document-storage-keyed-get.json +85 -0
  7. package/docs/builder-help/golden-examples/document-storage.json +30 -0
  8. package/docs/builder-help/golden-examples/meeting-transcript.json +29 -0
  9. package/docs/builder-help/golden-examples/repository-template.json +29 -0
  10. package/docs/builder-help/golden-examples/service-ticket.json +29 -0
  11. package/docs/builder-help/platform-roles.json +98 -0
  12. package/docs/builder-help/resource-type-catalog.json +402 -0
  13. package/lib/api/configuration.api.js +131 -0
  14. package/lib/api/system-secrets.api.js +72 -0
  15. package/lib/app/run-docker-fallback.js +6 -1
  16. package/lib/app/run-helpers.js +2 -1
  17. package/lib/app/run-parameter-sync.js +142 -0
  18. package/lib/build/docker-build-args.js +5 -2
  19. package/lib/build/index.js +3 -2
  20. package/lib/build/standard-docker-build.js +2 -2
  21. package/lib/cli/setup-app.js +5 -0
  22. package/lib/cli/setup-environment.js +156 -0
  23. package/lib/commands/datasource-capability-upsert-cli.js +112 -0
  24. package/lib/commands/datasource-capability.js +4 -2
  25. package/lib/commands/env-secret-context.js +113 -0
  26. package/lib/commands/env-secret-list.js +200 -0
  27. package/lib/commands/env-secret-push-confirm.js +54 -0
  28. package/lib/commands/env-secret-push-run.js +227 -0
  29. package/lib/commands/env-secret-push.js +168 -0
  30. package/lib/commands/repair-datasource-apply.js +2 -0
  31. package/lib/commands/repair-datasource-keyed-document.js +122 -0
  32. package/lib/commands/repair-datasource-run.js +1 -0
  33. package/lib/commands/setup-modes.js +1 -8
  34. package/lib/commands/setup-prompts.js +2 -180
  35. package/lib/commands/verify-operations-skip-e2e.js +25 -1
  36. package/lib/commands/verify-operations-steps.js +13 -1
  37. package/lib/commands/wizard-config-normalizer.js +7 -4
  38. package/lib/commands/wizard-core.js +5 -157
  39. package/lib/commands/wizard-file-saving.js +163 -0
  40. package/lib/core/env-platform-expand.js +5 -1
  41. package/lib/core/secrets-env-content.js +5 -1
  42. package/lib/core/secrets-env-write.js +10 -3
  43. package/lib/core/secrets-load.js +4 -2
  44. package/lib/datasource/binary-documents-validator.js +190 -0
  45. package/lib/datasource/capability/run-capability-upsert.js +202 -0
  46. package/lib/datasource/capability/upsert-ingredients.js +291 -0
  47. package/lib/datasource/capability/upsert-operations.js +138 -0
  48. package/lib/datasource/capability/upsert-test-scaffold.js +189 -0
  49. package/lib/datasource/validate.js +12 -5
  50. package/lib/generator/index.js +3 -0
  51. package/lib/lifecycle/product-model.js +4 -3
  52. package/lib/lifecycle/report-display.js +3 -2
  53. package/lib/parameters/infra-parameter-catalog.js +1 -1
  54. package/lib/programmatic/builder-help-enterprise-sync-fabrix.js +1 -1
  55. package/lib/programmatic/builder-help-governance.js +1 -1
  56. package/lib/programmatic/builder-help.js +1 -1
  57. package/lib/role-assistant/test-runner-workhub-answers.js +4 -1
  58. package/lib/role-assistant/test-runner-workhub-missing-fields.js +42 -0
  59. package/lib/role-assistant/test-runner-workhub-wait-stop.js +94 -0
  60. package/lib/role-assistant/test-runner-workhub.js +28 -19
  61. package/lib/schema/application-schema.json +14 -2
  62. package/lib/schema/external-datasource.schema.json +23 -3
  63. package/lib/schema/infra.parameter.yaml +388 -38
  64. package/lib/utils/compose-generate-docker-compose.js +7 -12
  65. package/lib/utils/datasource-binary-evidence.js +92 -0
  66. package/lib/utils/datasource-test-run-capability-scope.js +44 -1
  67. package/lib/utils/datasource-test-run-debug-display.js +2 -0
  68. package/lib/utils/datasource-test-run-display.js +8 -2
  69. package/lib/utils/datasource-test-run-issue-guidance.js +176 -0
  70. package/lib/utils/datasource-test-run-tty-log.js +2 -0
  71. package/lib/utils/env-copy.js +11 -10
  72. package/lib/utils/external-system-system-test-tty.js +3 -2
  73. package/lib/utils/image-tags.js +2 -2
  74. package/lib/utils/platform-kv-ref.js +1 -1
  75. package/lib/utils/prepare-local-data-mount.js +58 -0
  76. package/lib/utils/secrets-helpers.js +0 -1
  77. package/lib/utils/system-secret-mapping.js +125 -0
  78. package/lib/utils/test-log-writer.js +2 -1
  79. package/lib/validation/external-manifest-validator.js +5 -0
  80. package/lib/validation/openapi-contract-surface-validator.js +3 -1
  81. package/lib/validation/validate-external-file.js +5 -1
  82. package/package.json +4 -3
  83. package/templates/agent-kit/agent-kit.yaml +1 -1
  84. package/templates/agent-kit/skills/aifabrix-connected-system/SKILL.md +2 -1
  85. package/templates/agent-kit/skills/aifabrix-connected-system/references/delivery-gates.md +15 -0
  86. package/templates/agent-kit/skills/aifabrix-plan/SKILL.md +3 -2
  87. package/templates/agent-kit/skills/aifabrix-prove/SKILL.md +6 -2
  88. package/templates/agent-kit/skills/aifabrix-prove/references/evidence-lifecycle.md +22 -0
  89. package/templates/agent-kit/skills/aifabrix-role-assistant/SKILL.md +7 -1
  90. package/templates/agent-kit/skills/aifabrix-role-assistant/references/testing-playbook.md +117 -0
  91. package/templates/agent-kit/skills/shared/interaction.md +83 -0
  92. package/templates/agent-kit/skills/shared/status.md +3 -12
  93. package/templates/applications/builder-api/application.yaml +1 -1
  94. package/templates/applications/builder-api/env.template +5 -1
  95. package/templates/applications/dataplane/application.yaml +1 -1
  96. package/templates/applications/dataplane/env.template +10 -12
  97. package/templates/applications/keycloak/application.yaml +6 -1
  98. package/templates/applications/miso-controller/application.yaml +74 -2
  99. package/templates/applications/miso-controller/env.template +42 -3
  100. package/templates/applications/miso-controller/rbac.yaml +17 -0
  101. package/templates/external-system/external-datasource.yaml.hbs +7 -1
  102. package/templates/marketplace/main.json +4 -4
  103. package/templates/python/docker-compose.hbs +1 -1
  104. package/templates/agent-kit/skills/aifabrix-plan/references/interaction.md +0 -41
  105. /package/{lib/programmatic/help-content → docs/builder-help/content}/channel-onboarding.md +0 -0
  106. /package/{lib/programmatic/help-content → docs/builder-help/content}/cip-overview.md +0 -0
  107. /package/{lib/programmatic/help-content → docs/builder-help/content}/connected-system-ui.md +0 -0
  108. /package/{lib/programmatic/help-content → docs/builder-help/content}/dimensions-guide.md +0 -0
  109. /package/{lib/programmatic/help-content → docs/builder-help/content}/enterprise-sync-fabrix.md +0 -0
  110. /package/{lib/programmatic/help-content → docs/builder-help/content}/overview.md +0 -0
  111. /package/{lib/programmatic/help-content → docs/builder-help/content}/subscription-guide.md +0 -0
  112. /package/{lib/programmatic/help-content → docs/builder-help/content}/workflow.md +0 -0
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Map an application's `.env` variables onto Miso catalog keys.
3
+ *
4
+ * The `.env` is keyed by environment variable (`MORI_POLICY_PRIVATE_KEY`) while the system
5
+ * secrets API is keyed by catalog key (`secrets-policyPrivateKeyVault`). The mapping is not
6
+ * invented here: it is read from the application's own `env.template`, because the
7
+ * `NAME=kv://<catalogKey>` line is already the declaration that decides where the value is
8
+ * read from at runtime. A second table in the CLI would be free to drift from it.
9
+ *
10
+ * A variable whose template line is not a `kv://` reference is ordinary configuration, not a
11
+ * secret, and is skipped rather than pushed.
12
+ *
13
+ * Note this is the flat `kv://<catalogKey>` form used by the Controller's system secrets.
14
+ * The Dataplane's credential store uses `kv://<systemKey>/<path>`; see
15
+ * `credential-secrets-env-kv.js` for that one. They are not interchangeable.
16
+ *
17
+ * @fileoverview env.template kv:// declarations → catalog keys
18
+ * @author AI Fabrix Team
19
+ * @version 1.0.0
20
+ */
21
+
22
+ 'use strict';
23
+
24
+ /** `NAME=value`, ignoring blank lines, comments and `export ` prefixes. */
25
+ const ASSIGNMENT = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/;
26
+
27
+ /**
28
+ * Strip surrounding quotes and trailing whitespace from an env value.
29
+ * @param {string} raw - Raw right-hand side
30
+ * @returns {string} Cleaned value
31
+ */
32
+ function cleanValue(raw) {
33
+ const trimmed = String(raw === undefined || raw === null ? '' : raw).trim();
34
+ if (trimmed.length >= 2) {
35
+ const first = trimmed[0];
36
+ const last = trimmed[trimmed.length - 1];
37
+ if ((first === '"' && last === '"') || (first === '\'' && last === '\'')) {
38
+ return trimmed.slice(1, -1);
39
+ }
40
+ }
41
+ return trimmed;
42
+ }
43
+
44
+ /**
45
+ * Parse `NAME=value` lines into a Map, last assignment winning.
46
+ * @param {string} content - File content
47
+ * @returns {Map<string, string>} Variable name → value
48
+ */
49
+ function parseEnvAssignments(content) {
50
+ const out = new Map();
51
+ for (const line of String(content || '').split(/\r?\n/)) {
52
+ if (!line || /^\s*#/.test(line)) {
53
+ continue;
54
+ }
55
+ const match = line.match(ASSIGNMENT);
56
+ if (match) {
57
+ out.set(match[1], cleanValue(match[2]));
58
+ }
59
+ }
60
+ return out;
61
+ }
62
+
63
+ /**
64
+ * Catalog keys declared by an `env.template`, keyed by environment variable name.
65
+ * Only `kv://` lines are secrets; everything else is skipped.
66
+ * @param {string} templateContent - env.template content
67
+ * @returns {Map<string, string>} Variable name → catalog key
68
+ */
69
+ function catalogKeysFromTemplate(templateContent) {
70
+ const out = new Map();
71
+ for (const [name, value] of parseEnvAssignments(templateContent)) {
72
+ if (!value.startsWith('kv://')) {
73
+ continue;
74
+ }
75
+ const catalogKey = value.slice('kv://'.length).trim();
76
+ if (catalogKey && !catalogKey.includes('/')) {
77
+ out.set(name, catalogKey);
78
+ }
79
+ }
80
+ return out;
81
+ }
82
+
83
+ /**
84
+ * Pair the values in a `.env` with the catalog keys its `env.template` declares.
85
+ *
86
+ * Skipped rows are returned rather than dropped, so the command can say why a variable was
87
+ * not pushed instead of silently ignoring it.
88
+ *
89
+ * @param {string} envContent - Operator's .env content
90
+ * @param {string} templateContent - The application's env.template content
91
+ * @param {Object} [options] - `only` restricts to one variable name
92
+ * @returns {{ pushable: Array<Object>, skipped: Array<Object> }} Rows carrying value and catalog key
93
+ */
94
+ function mapEnvToCatalogKeys(envContent, templateContent, options = {}) {
95
+ const declared = catalogKeysFromTemplate(templateContent);
96
+ const values = parseEnvAssignments(envContent);
97
+ const only = options.only ? String(options.only).trim() : '';
98
+ const pushable = [];
99
+ const skipped = [];
100
+ for (const [name, value] of values) {
101
+ if (only && name !== only) {
102
+ continue;
103
+ }
104
+ const catalogKey = declared.get(name);
105
+ if (!catalogKey) {
106
+ skipped.push({ name, reason: 'not a kv:// reference in env.template' });
107
+ continue;
108
+ }
109
+ if (!value) {
110
+ skipped.push({ name, catalogKey, reason: 'no value in the env file' });
111
+ continue;
112
+ }
113
+ pushable.push({ name, catalogKey, value });
114
+ }
115
+ if (only && pushable.length === 0 && skipped.length === 0) {
116
+ skipped.push({ name: only, reason: 'not present in the env file' });
117
+ }
118
+ return { pushable, skipped };
119
+ }
120
+
121
+ module.exports = {
122
+ parseEnvAssignments,
123
+ catalogKeysFromTemplate,
124
+ mapEnvToCatalogKeys
125
+ };
@@ -9,6 +9,7 @@
9
9
 
10
10
  const fs = require('fs').promises;
11
11
  const path = require('path');
12
+ const { sanitizeBinaryEvidence } = require('./datasource-binary-evidence');
12
13
 
13
14
  /**
14
15
  * Prepare object for JSON serialization (handles circular refs)
@@ -45,7 +46,7 @@ async function writeTestLog(appKey, data, logType = 'test-integration', integrat
45
46
  const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
46
47
  const filename = `${logType}-${timestamp}.json`;
47
48
  const filePath = path.join(logsDir, filename);
48
- const sanitized = sanitizeForLog(data);
49
+ const sanitized = sanitizeForLog(sanitizeBinaryEvidence(data));
49
50
  await fs.writeFile(filePath, JSON.stringify(sanitized, null, 2), 'utf8');
50
51
  return filePath;
51
52
  }
@@ -16,6 +16,7 @@ const path = require('path');
16
16
  const { formatValidationErrors } = require('../utils/error-formatter');
17
17
  const { validateFieldReferences } = require('../datasource/field-reference-validator');
18
18
  const { validateAbac } = require('../datasource/abac-validator');
19
+ const { validateBinaryDocumentsContract } = require('../datasource/binary-documents-validator');
19
20
  const { validateManifestRuntimeConfiguration } = require('./runtime-configuration-rules');
20
21
  const { validateAppContractSurface } = require('./openapi-contract-surface-validator');
21
22
 
@@ -147,9 +148,13 @@ function validateDatasources(manifest, ajv, externalDatasourceSchema, errors, wa
147
148
  } else {
148
149
  const fieldRefErrors = validateFieldReferences(datasource);
149
150
  const abacErrors = validateAbac(datasource);
151
+ const binaryDocuments = validateBinaryDocumentsContract(datasource);
150
152
  const prefix = `Datasource ${index + 1} (${datasource.key || 'unknown'}): `;
151
153
  fieldRefErrors.forEach(e => errors.push(prefix + e));
152
154
  abacErrors.forEach(e => errors.push(prefix + e));
155
+ // Codes are the dataplane's, so the offline answer matches the upload answer.
156
+ binaryDocuments.errors.forEach(e => errors.push(`${prefix}${e.code}: ${e.message}`));
157
+ binaryDocuments.warnings.forEach(w => warnings.push(`${prefix}${w.code}: ${w.message}`));
153
158
  }
154
159
  });
155
160
  }
@@ -426,5 +426,7 @@ module.exports = {
426
426
  validateDatasourceFileContractSurface,
427
427
  validateVendorOperationContract,
428
428
  validateServiceContractDatasourceContracts,
429
- findVendorOperation
429
+ findVendorOperation,
430
+ resolveVendorOpenApiSpec,
431
+ inferIntegrationContextFromPath
430
432
  };
@@ -111,11 +111,15 @@ function validateDatasourceFileExtras(parsed, filePath) {
111
111
  const { collectExternalDatasourceWarnings } = require('./datasource-warnings');
112
112
  const { validateDatasourceFileContractSurface } = require('./openapi-contract-surface-validator');
113
113
  const errors = [...validateFieldReferences(parsed), ...validateAbac(parsed)];
114
+ const { validateBinaryDocumentsContract } = require('../datasource/binary-documents-validator');
115
+ const binary = validateBinaryDocumentsContract(parsed);
116
+ errors.push(...binary.errors.map(issue => `${issue.code}: ${issue.message}`));
114
117
  const contractSurface = validateDatasourceFileContractSurface(parsed, filePath);
115
118
  errors.push(...contractSurface.errors);
116
119
  const warnings = [
117
120
  ...collectExternalDatasourceWarnings(parsed),
118
- ...contractSurface.warnings
121
+ ...contractSurface.warnings,
122
+ ...binary.warnings.map(issue => `${issue.code}: ${issue.message}`)
119
123
  ];
120
124
  return { errors, warnings };
121
125
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aifabrix/builder",
3
- "version": "2.60.0",
3
+ "version": "2.61.2",
4
4
  "description": "AI Fabrix Builder — CLI and developer scripts (pnpm + af)",
5
5
  "main": "lib/index.js",
6
6
  "bin": {
@@ -10,6 +10,7 @@
10
10
  "files": [
11
11
  "bin/aifabrix.js",
12
12
  "lib/",
13
+ "docs/builder-help/",
13
14
  "templates/",
14
15
  "README.md",
15
16
  "LICENSE"
@@ -24,7 +25,7 @@
24
25
  "dev-deploy": "node scripts/pnpm/dev-deploy.mjs",
25
26
  "af": "node scripts/pnpm/af.mjs",
26
27
  "check-quiet": "node scripts/pnpm/check-quiet.mjs",
27
- "agent-skills:sync": "node scripts/pnpm/agent-skills-sync.mjs",
28
+ "agent-skills:sync": "node scripts/pnpm/agent-skills-sync.mjs --codex-home",
28
29
  "agent-skills:check": "node scripts/pnpm/agent-skills-sync.mjs --check",
29
30
  "agent-skills:sync:codex": "node scripts/pnpm/agent-skills-sync.mjs --codex-home",
30
31
  "agent-skills:test": "node --test scripts/pnpm/agent-skills-sync.test.mjs",
@@ -131,7 +132,7 @@
131
132
  }
132
133
  },
133
134
  "dependencies": {
134
- "@aifabrix/miso-client": "4.23.1",
135
+ "@aifabrix/miso-client": "5.0.3",
135
136
  "@azure/identity": "4.11.1",
136
137
  "adm-zip": "^0.6.1",
137
138
  "ajv": "^8.20.0",
@@ -1,5 +1,5 @@
1
1
  schemaVersion: "1"
2
- kitVersion: "1.2.0"
2
+ kitVersion: "1.2.1"
3
3
  minimumBuilderVersion: "2.54.2"
4
4
  skills:
5
5
  - aifabrix-plan
@@ -20,7 +20,7 @@ Resolve phase: explicit argument → ask. Package state informs the recommendati
20
20
  the action.
21
21
 
22
22
  Stop at the phase gate. Do not run the next phase without `next-yes`
23
- ([interaction.md](../aifabrix-plan/references/interaction.md)).
23
+ ([interaction.md](../shared/interaction.md)).
24
24
 
25
25
  | Phase | Entry | Success |
26
26
  | --- | --- | --- |
@@ -67,6 +67,7 @@ System key: argument → active plan → sole `integration/` folder → ask once
67
67
 
68
68
  ## References
69
69
 
70
+ - [interaction.md](../shared/interaction.md) — native selection controls, routes, and phase gates
70
71
  - [status.md](../shared/status.md) — read-only default, route options, status matrix
71
72
  - [delivery-gates.md](references/delivery-gates.md) — BID/wizard/repair, upload vs deploy, tests, identity, protection
72
73
  - [contract-checklist.md](references/contract-checklist.md) — exposed, FK, viewpoints, RBAC/ABAC
@@ -39,6 +39,21 @@ If `integration/<systemKey>/deploy.js` exists, you may run it as the publish lad
39
39
 
40
40
  Never mark live E2E pass when it did not run.
41
41
 
42
+ ## Upsert authoring and warnings
43
+
44
+ When upsert is explicitly required, first run
45
+ `aifabrix datasource capability upsert <file-or-key> --dry-run --json`. Apply a
46
+ fix automatically only when the finding identifies a deterministic local
47
+ manifest change and the active phase authorizes mutation. Rerun the exact
48
+ failed command before broader validation.
49
+
50
+ Every open finding must state the observed condition, business consequence,
51
+ safe action, prevention, residual risk, and exact rerun. A source API that
52
+ cannot constrain the complete business identity is not AI-fixable: keep valid
53
+ separate create/update capabilities, report duplicate or wrong-update risk,
54
+ and withhold verified upsert. Never invent a lookup, weaken the two-write
55
+ no-duplicate assertion, or hide the warning behind another passing test.
56
+
42
57
  ## Identity and protection order
43
58
 
44
59
  1. `aifabrix auth status` — if unauthenticated, [login.md](../../shared/login.md)
@@ -16,7 +16,7 @@ Named with no specification, report what exists and ask; do not start writing a
16
16
  an inferred spec ([status.md](../shared/status.md)).
17
17
 
18
18
  Score completeness with [challenge-checklist.md](references/challenge-checklist.md).
19
- Next-step interaction: [interaction.md](references/interaction.md).
19
+ Structured choices and phase gates: [interaction.md](../shared/interaction.md).
20
20
  Host runtimes (local vs SSH): [hosts.md](../shared/hosts.md).
21
21
  CLI login from chat: [login.md](../shared/login.md).
22
22
 
@@ -32,7 +32,8 @@ Do not start Connected System validate until **PLAN_READY** and the user picks `
32
32
 
33
33
  1. Collect the spec the user named. Do not mine platform repos as the spec.
34
34
  2. Inventory without adding: purpose, sources, entities, relationships, role labels, operations, Viewpoints, Evidence, identity join. Missing sections → `TBD` plus an Open question.
35
- 3. Challenge required rows. AskQuestion every MISSING required row. Authority and identity cannot be guessed.
35
+ 3. Challenge required rows. Use the structured question control for every MISSING required
36
+ row. Authority and identity cannot be guessed.
36
37
  4. Write or update `.cursor/plans/{major}.0-{slug}.plan.md` using the template H2 order. Same capability updates in place.
37
38
  5. Report status and path. On PLAN_READY, offer validate — do not run it without `next-yes`.
38
39
 
@@ -38,8 +38,10 @@ business-case readiness. None of them, alone or together, makes prove READY.
38
38
 
39
39
  Every phase **must** update [learning-template.md](references/learning-template.md).
40
40
  Evidence rules: [evidence-lifecycle.md](references/evidence-lifecycle.md).
41
+ Role Assistant test execution and diagnosis:
42
+ [testing-playbook.md](../aifabrix-role-assistant/references/testing-playbook.md).
41
43
  Demo shape: [demo-template.md](references/demo-template.md).
42
- Next-step: [interaction.md](../aifabrix-plan/references/interaction.md).
44
+ Structured choices and phase gates: [interaction.md](../shared/interaction.md).
43
45
  Host runtimes (local vs SSH): [hosts.md](../shared/hosts.md).
44
46
  CLI login from chat: [login.md](../shared/login.md).
45
47
 
@@ -60,7 +62,9 @@ Repeatable: demo, Knowledge, candidate Evidence, tests. Do not refuse because va
60
62
 
61
63
  ## Prove
62
64
 
63
- Run assistant tests. Record observations and gap owner (`none` | `product-gap` | `missing-customer-fact` | `scope-decision`).
65
+ Run assistant tests using the testing playbook. Record the business verdict,
66
+ execution reference, and gap owner (`none` | `product-gap` |
67
+ `missing-customer-fact` | `scope-decision`).
64
68
  Happy + safe-stop coverage for authority scenarios.
65
69
  Never report candidates as certified.
66
70
 
@@ -49,6 +49,25 @@ Promote candidate → governed Evidence only when:
49
49
  3. Contract validation + certification path for Evidence completed (public Evidence Fabrix / operate-first RA docs)
50
50
  4. learning.md records promotion date + commit
51
51
 
52
+ ## Human authority and applied proof
53
+
54
+ Keep these states distinct:
55
+
56
+ | State | What it proves |
57
+ | --- | --- |
58
+ | Candidate or proposal | Draft content exists; it is not governed Evidence |
59
+ | Certified | The applicable human governance decision completed |
60
+ | Active | The product may supply the Evidence to execution |
61
+ | Applied | A recorded execution shows the Evidence affected the result |
62
+
63
+ An agent may prepare candidates, execute authorized source cases, and inspect a
64
+ proposal. It must pause before certifying, activating, rejecting, or
65
+ deactivating Evidence unless the current user explicitly authorizes that action
66
+ and the product workflow permits it. Record the pause as `BLOCKED_BY_HUMAN`, not
67
+ as a failed test. After the human gate, rerun the case and prove Applied Evidence
68
+ from execution evidence; catalog presence is not Applied proof. Follow the
69
+ [Role Assistant testing playbook](../../aifabrix-role-assistant/references/testing-playbook.md).
70
+
52
71
  ## Tests
53
72
 
54
73
  For each in-scope scenario ID:
@@ -66,3 +85,6 @@ Prefer `role-assistant/ra-<roleKey>/tests/<suiteId>/` in this customer repo (pac
66
85
  - Hiding process law in Knowledge
67
86
  - Uploading candidates as if certified
68
87
  - Skipping safe-stop coverage for authority scenarios
88
+ - Certifying, activating, rejecting, or deactivating Evidence without the
89
+ current user's explicit authority
90
+ - Reporting catalog presence as proof that Evidence was Applied
@@ -9,8 +9,11 @@ description: >
9
9
  # aifabrix-role-assistant
10
10
 
11
11
  See [package-boundary.md](references/package-boundary.md) and nested `role-assistant/AGENTS.md`.
12
+ For test execution, verdicts, fixtures, and diagnosis, follow
13
+ [testing-playbook.md](references/testing-playbook.md).
12
14
  Host runtimes (local vs SSH): [hosts.md](../shared/hosts.md).
13
15
  CLI login from chat: [login.md](../shared/login.md).
16
+ Structured choices and phase gates: [interaction.md](../shared/interaction.md).
14
17
 
15
18
  Named with no task, report status and stop: [status.md](../shared/status.md).
16
19
 
@@ -47,7 +50,9 @@ substitutes for it.
47
50
 
48
51
  1. `aifabrix download <catalogRoleOrRaKey>` before editing an existing assistant.
49
52
  2. Author settings, Knowledge, Evidence, tests, and sidecars per current Builder contracts. Read `aifabrix role-assistant --help`.
50
- 3. `aifabrix role-assistant test …` is allowed without local RA publish.
53
+ 3. `aifabrix role-assistant test …` is allowed without local RA publish. Apply
54
+ the testing playbook and inspect hard business assertions before reporting
55
+ READY or VERIFIED.
51
56
  4. Upload/deploy RA only when the user explicitly asks in this turn.
52
57
  5. Report results honestly.
53
58
 
@@ -62,3 +67,4 @@ substitutes for it.
62
67
  ## Trigger examples
63
68
 
64
69
  - Create or update the Finance Controller Role Assistant
70
+ - Test or diagnose the Finance Controller Role Assistant
@@ -0,0 +1,117 @@
1
+ # Role Assistant testing and diagnosis
2
+
3
+ Public concepts: https://docs.aifabrix.ai/docs/role-assistants
4
+ Exact commands, fields, and flags: run `aifabrix role-assistant test --help` with
5
+ the installed Builder version.
6
+
7
+ Use this playbook for live Role Assistant cases. A successful command is not
8
+ enough: the observed business outcome, authority boundary, capabilities, Work
9
+ Result, and resource changes must match the case.
10
+
11
+ ## Preconditions
12
+
13
+ - Authenticate to the intended environment and identify the package and cases
14
+ root before execution.
15
+ - Confirm every required Connected System is published and certified, its
16
+ required capabilities are available, and worker availability is known.
17
+ - Record the actor and business role, mutation scope, designated test subjects,
18
+ and cleanup rule before a mutating case.
19
+ - Treat missing auth, worker availability, capability, fixture, or required
20
+ human action as `BLOCKED` with the exact prerequisite.
21
+
22
+ ## Execution ladder
23
+
24
+ 1. Validate the package and use `--list-cases` to confirm discovery.
25
+ 2. Run one focused case with `--case ... --json`.
26
+ 3. Inspect lifecycle and final Runtime status, questions or approvals,
27
+ `expected.capabilities`, Work Result completion, resource changes, and
28
+ Evidence use. Do not rely on the process exit or wrapper verdict alone.
29
+ 4. Correct the owning layer, rerun the exact case, and then run its suite.
30
+ 5. Run broader suites only after the focused case is stable.
31
+ 6. Record environment, timestamp, package/source revision, command,
32
+ execution/correlation reference, verdict class, and gap owner in
33
+ `learning/learning.md` or the plan-defined evidence location.
34
+
35
+ ## Verdict law
36
+
37
+ | Observation | Verdict |
38
+ | --- | --- |
39
+ | Hard assertions and intended business outcome pass | `PASS` |
40
+ | Intended denial or safe stop occurs with no forbidden mutation | `PASS_EXPECTED_STOP` |
41
+ | `expected.soft: true` turns a mismatch into a warning | `GAP`; never `VERIFIED` |
42
+ | A prerequisite or required human action is absent | `BLOCKED` with the missing row |
43
+ | Runtime or CLI is defective and the run is reproducible | `PRODUCT_GAP` |
44
+ | Role Assistant, Knowledge, or Evidence content is wrong while the product behaves correctly | `PACKAGE_GAP` |
45
+
46
+ An exit code `0`, CLI `PASS`, lifecycle smoke, or certification level cannot
47
+ replace the applicable business verdict. An expected safe stop is not ordinary
48
+ success: name the denied or waiting state and prove that no forbidden mutation
49
+ occurred.
50
+
51
+ ## Assertion quality
52
+
53
+ - Release and prove cases use hard lifecycle and Result assertions. Soft cases
54
+ are exploratory and cannot establish READY or VERIFIED.
55
+ - Mutation cases assert the exact required and forbidden capabilities,
56
+ `expected.honesty.requireWorkResult`, completion, and a meaningful
57
+ `expected.honesty.minResourceChanges` value.
58
+ - Read-only cases forbid mutation capabilities. Authority cases assert the
59
+ intended denial, question, approval wait, or safe stop.
60
+ - Do not weaken an assertion to accommodate a failure. Classify the gap and
61
+ repair its owner.
62
+
63
+ ## Fixtures, identity, and cleanup
64
+
65
+ - Stable shared identities are read-only unless the integration README names
66
+ them as approved mutable subjects.
67
+ - Give mutable cases collision-safe explicit values. Generate and write those
68
+ values into the case through normal repository editing before the run; do not
69
+ claim that an interpolation token exists unless current CLI help, schema,
70
+ source, and tests establish it.
71
+ - Share an identity across cases only for a documented suite dependency.
72
+ - Never inject a hidden primary key, actor, business role, API key, or
73
+ authorization dimension to make a case pass.
74
+ - Cleanup must be explicit, bounded to the designated subject, and separately
75
+ authorized when destructive.
76
+
77
+ ## ABAC and replay
78
+
79
+ Every authority-sensitive scenario needs an allowed case and an outside-scope
80
+ or denied case. Nested calls must preserve the same actor and business-role
81
+ context. Ambiguous identity must ask or stop safely, never select a convenient
82
+ record. Retry and replay cases must prove there is no duplicate resource and no
83
+ double-counted Evidence.
84
+
85
+ ## Human Evidence boundary
86
+
87
+ Agents may author candidates, run source executions, and inspect proposals when
88
+ authorized. They must not certify, activate, reject, or deactivate Evidence for
89
+ a human unless the current user explicitly authorizes that product action and
90
+ the product workflow permits it. A run paused at certification or activation is
91
+ `BLOCKED_BY_HUMAN`, not failed. Later proof must show Evidence was actually
92
+ Applied in execution; catalog presence alone is insufficient. See
93
+ [Evidence lifecycle](../../aifabrix-prove/references/evidence-lifecycle.md).
94
+
95
+ ## Root-cause routing
96
+
97
+ | Finding | Owner / next action |
98
+ | --- | --- |
99
+ | Auth, environment, or worker unavailable | Report the exact prerequisite |
100
+ | Duplicate or stale test data | Fixture owner; preserve the trail and repair safely |
101
+ | Soft or incomplete expectation | Case author; strengthen without changing product behavior |
102
+ | Missing operation, certification, or capability | Connected System package |
103
+ | Runtime loop, wrong identity binding, or false success | Product gap with execution evidence |
104
+ | Wrong prompt, Knowledge, or Evidence definition | Role Assistant package |
105
+ | Evidence certification or activation required | Human governance gate |
106
+
107
+ Do not conceal a lower-layer gap in Knowledge or build a Role Assistant-local
108
+ imitation of a missing Connected System capability.
109
+
110
+ For an upsert finding, route local manifest repair to Connected System
111
+ ownership and rerun the exact failed proof. If the external source cannot
112
+ support exact business-identity lookup or uniqueness, state what happened,
113
+ what cannot be repaired by AI, the duplicate or wrong-record-update risk, the
114
+ safe alternative, and how future connectors should prevent it. Keep readiness
115
+ blocked or qualified as reported by validation; never substitute create,
116
+ weaken the no-duplicate assertion, or clear the warning because an unrelated
117
+ case passed.
@@ -0,0 +1,83 @@
1
+ # Structured choices and phase gates
2
+
3
+ This file owns interactive choices for every Agent Kit skill. Use the same behavior in
4
+ Cursor, Claude, and Codex; host-specific tool names do not change the workflow.
5
+
6
+ ## Show choices in the host control
7
+
8
+ When the user must choose between discrete actions, invoke the host's native structured
9
+ question control instead of printing a `Choose:` block in chat:
10
+
11
+ | Host | Native control |
12
+ | --- | --- |
13
+ | Cursor | `AskQuestion` |
14
+ | Claude | `AskUserQuestion` |
15
+ | Codex | `request_user_input` |
16
+
17
+ Give the control a short header, one direct question, and mutually exclusive options.
18
+ Put the recommended option first, label it `(Recommended)`, and add one short description
19
+ of its effect. Keep the stable option ids below as the workflow result even when a host
20
+ returns a label rather than an id.
21
+
22
+ If the host supplies its own free-form **Other** choice, map that response to the matching
23
+ `*-other` id. Otherwise include an explicit **Something else** option. If no structured
24
+ question control is available, show the same choices as a numbered list and wait for one
25
+ answer. Never continue merely because an option was recommended.
26
+
27
+ Do not open a control when the user already made an unambiguous choice in the current
28
+ turn. Treat that choice exactly like the corresponding control result.
29
+
30
+ ## Bare-invocation routes
31
+
32
+ Ask once and proceed only on an explicit choice.
33
+
34
+ | Option id | Control label | Means |
35
+ | --- | --- | --- |
36
+ | `route-normal` | Run normal path (Recommended) | Run the normal path for this skill through to its gate, stopping at each phase gate |
37
+ | `route-check` | Inspect and test only | Run validation, checks, and status with no publish or promotion |
38
+ | `route-other` | Something else | Collect the action in the control's free-form response |
39
+ | `next-stop` | Stop here | End without further action |
40
+
41
+ `route-normal` still stops at every phase gate and still needs `next-yes` to continue. It
42
+ is a route, not permission to run the whole lifecycle unattended.
43
+
44
+ ## After success
45
+
46
+ Offer the next eligible phase with the structured question control. Proceed only on
47
+ `next-yes`.
48
+
49
+ Shared option ids: `next-yes` · `next-no` · `next-stop`.
50
+
51
+ | Completed | Next offer |
52
+ | --- | --- |
53
+ | aifabrix-plan PLAN_READY | connected-system validate |
54
+ | connected-system READY | connected-system build |
55
+ | connected-system BUILT | connected-system publish |
56
+ | connected-system PASS or PASS_WITH_SKIPS | archive (separate) and/or prove validate |
57
+ | prove READY / BUILT / UPDATED | prove next phase |
58
+ | prove PASS or PASS_WITH_SKIPS | iterate validate/build |
59
+
60
+ Archive is a distinct user decision (`archive-yes` / `archive-no`). Never archive as a
61
+ side effect of PASS.
62
+
63
+ ## On gaps
64
+
65
+ - NEEDS_DECISIONS: ask about every challenge row with the structured control. No
66
+ `cust-next`.
67
+ - BLOCKED / FAIL / NEEDS_FIXES / ABORTED: do not offer the next phase as if success.
68
+
69
+ A phase gate is per-gate, not overall. Offer the next phase only when the **Delivery** row
70
+ supports it; a passing package gate beside `Delivery: NEEDS_FIXES` is not success and the
71
+ offer must name what is still open.
72
+
73
+ ## Phase detection (connected-system and prove)
74
+
75
+ 1. Explicit phase from the user
76
+ 2. Ask with the structured control, offering the bare-invocation routes above
77
+
78
+ There is no third step. Package and plan state decide what you *recommend*, never what you
79
+ run: a bare invocation reports status and stops ([status.md](status.md)). Inferring "the
80
+ safe next eligible phase" is what makes a skill start working before the user has said
81
+ what they want.
82
+
83
+ Never silently run the following phase after success.
@@ -25,18 +25,9 @@ they cannot see coming.
25
25
 
26
26
  ## Offer the route, do not choose it
27
27
 
28
- Ask once, with these options. Proceed only on an explicit choice.
29
-
30
- | Option id | Means |
31
- | --- | --- |
32
- | `route-normal` | Run the normal path for this skill through to its gate, stopping at each phase gate |
33
- | `route-check` | Inspect and test only — validation, checks and status, no publish or promotion |
34
- | `route-other` | Something else; ask what |
35
- | `next-stop` | Stop here |
36
-
37
- `route-normal` still stops at every phase gate and still needs `next-yes` to continue
38
- ([interaction.md](../aifabrix-plan/references/interaction.md)). It is a route, not a
39
- licence to run the whole lifecycle unattended.
28
+ Use the host's native selection control and the canonical route options in
29
+ [interaction.md](interaction.md). Proceed only on an explicit choice. Do not print a
30
+ `Choose:` block when a structured question control is available.
40
31
 
41
32
  ## Always report the combined matrix
42
33
 
@@ -5,7 +5,7 @@ app:
5
5
  description: 'Business Transformation services — HTTP orchestration for connected-system workspace lifecycle via Dataplane Enterprise MCP and governance APIs.'
6
6
  type: webapp
7
7
  language: typescript
8
- version: 2.60.0
8
+ version: 2.61.2
9
9
 
10
10
  # Image Configuration
11
11
  image:
@@ -23,11 +23,15 @@ MAX_UPLOAD_TIMEOUT_MS=300000
23
23
  # =============================================================================
24
24
  # url:// resolves after kv:// at resolve time (see docs/configuration/resolve-running-urls.md)
25
25
 
26
+ # Governed configuration uses per-application client credentials by default. The SDK loads
27
+ # its bootstrap snapshot and refreshes it automatically within two minutes; consumers decide
28
+ # whether a changed key also requires an internal client or resource to be recreated.
29
+ MISO_AUTH_MODE=client-credentials
26
30
  # Registered OAuth client (populated by aifabrix app register / bootstrap — same as dataplane)
27
31
  MISO_CLIENTID=kv://builder-api-client-idKeyVault
28
32
  MISO_CLIENTSECRET=kv://builder-api-client-secretKeyVault
29
33
 
30
- # Internal: controller API for token validation (supports all miso-controller auth modes)
34
+ # Private service-to-service controller origin. Public or remote controller origins require HTTPS.
31
35
  MISO_CONTROLLER_URL=url://miso-controller-internal
32
36
  # Public: OAuth profile and remaining-step links shown to vendors (not Docker DNS)
33
37
  MISO_CONTROLLER_PUBLIC_URL=url://miso-controller-public
@@ -5,7 +5,7 @@ app:
5
5
  description: "AI Fabrix Dataplane is a secure, in-tenant integration and automation layer that supplies governed, normalized, and explainable enterprise data to AI agents. Using CIP as a declarative standard, it enforces RBAC and ABAC, executes integrations, and exposes trusted data via MCP and OpenAPI."
6
6
  type: webapp
7
7
  language: python # Explicitly specify Python language
8
- version: 2.0.74
8
+ version: 2.0.79
9
9
  # Image Configuration
10
10
  # Set tag to match your build (example: aifabrix build dataplane -t 1.0.0).
11
11
  # Registry is required so the controller can pull the image (avoids docker-not-found on the controller host).