procesio-cli 0.1.1__py3-none-any.whl
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.
- procesio_cli/__init__.py +18 -0
- procesio_cli/_cli.py +71 -0
- procesio_cli/agents/__init__.py +0 -0
- procesio_cli/agents/_lib/__init__.py +0 -0
- procesio_cli/agents/_lib/actiondef.py +24 -0
- procesio_cli/agents/_lib/errors.py +40 -0
- procesio_cli/agents/_lib/reversibility.py +236 -0
- procesio_cli/agents/_lib/toolrunner.py +141 -0
- procesio_cli/agents/connector-builder/CONNECTOR-BUILDER-PLAYBOOK.md +62 -0
- procesio_cli/agents/connector-builder/CONNECTOR-BUILDER-PROCESIO-INTEROP.md +76 -0
- procesio_cli/agents/connector-builder/CONNECTOR-BUILDER-TROUBLESHOOTING.md +60 -0
- procesio_cli/agents/connector-builder/README.md +51 -0
- procesio_cli/agents/connector-builder/agent.yaml +61 -0
- procesio_cli/agents/connector-builder/context.py +19 -0
- procesio_cli/agents/connector-builder/handlers/__init__.py +1 -0
- procesio_cli/agents/connector-builder/handlers/checklist.py +71 -0
- procesio_cli/agents/connector-builder/handlers/guidance.py +37 -0
- procesio_cli/agents/connector-builder/handlers/nextstep.py +221 -0
- procesio_cli/agents/connector-builder/handlers/status.py +35 -0
- procesio_cli/agents/connector-builder/knowledge.py +47 -0
- procesio_cli/agents/connector-builder/main.py +93 -0
- procesio_cli/agents/connector-builder/tests/conftest.py +95 -0
- procesio_cli/agents/connector-builder/tests/test_cba_agent.py +148 -0
- procesio_cli/agents/orchestrator/__init__.py +0 -0
- procesio_cli/agents/orchestrator/bootstraplib.py +166 -0
- procesio_cli/agents/procesio/IMPLEMENTATION-PATTERNS/00-INDEX.md +60 -0
- procesio_cli/agents/procesio/IMPLEMENTATION-PATTERNS/01-PROCESSES.md +230 -0
- procesio_cli/agents/procesio/IMPLEMENTATION-PATTERNS/02-FORMS.md +287 -0
- procesio_cli/agents/procesio/IMPLEMENTATION-PATTERNS/03-INTEGRATIONS.md +384 -0
- procesio_cli/agents/procesio/IMPLEMENTATION-PATTERNS/04-DATABASE.md +293 -0
- procesio_cli/agents/procesio/PROCESIO-API-RELIABILITY-DOCTRINE.md +113 -0
- procesio_cli/agents/procesio/PROCESIO-BEST-PRACTICES.md +316 -0
- procesio_cli/agents/procesio/PROCESIO-BUILD-AND-TEST-PLAYBOOK.md +217 -0
- procesio_cli/agents/procesio/PROCESIO-DATASTORE.md +72 -0
- procesio_cli/agents/procesio/PROCESIO-ENVIRONMENTS.md +62 -0
- procesio_cli/agents/procesio/PROCESIO-SCHEDULING.md +47 -0
- procesio_cli/agents/procesio/PROCESIO-VISUAL-ORGANIZATION.md +175 -0
- procesio_cli/agents/procesio/README.md +97 -0
- procesio_cli/agents/procesio/__init__.py +0 -0
- procesio_cli/agents/procesio/agent.yaml +73 -0
- procesio_cli/agents/procesio/audit.py +226 -0
- procesio_cli/agents/procesio/checklist.py +135 -0
- procesio_cli/agents/procesio/context.py +19 -0
- procesio_cli/agents/procesio/handlers/__init__.py +0 -0
- procesio_cli/agents/procesio/handlers/audit.py +39 -0
- procesio_cli/agents/procesio/handlers/checklist.py +34 -0
- procesio_cli/agents/procesio/handlers/guidance.py +36 -0
- procesio_cli/agents/procesio/handlers/status.py +33 -0
- procesio_cli/agents/procesio/handlers/verify.py +39 -0
- procesio_cli/agents/procesio/knowledge.py +115 -0
- procesio_cli/agents/procesio/main.py +89 -0
- procesio_cli/agents/procesio/tests/__init__.py +0 -0
- procesio_cli/agents/procesio/tests/conftest.py +62 -0
- procesio_cli/agents/procesio/tests/test_audit.py +91 -0
- procesio_cli/agents/procesio/tests/test_checklist.py +28 -0
- procesio_cli/agents/procesio/tests/test_guidance.py +78 -0
- procesio_cli/agents/procesio/tests/test_manifest_sync.py +48 -0
- procesio_cli/agents/procesio/tests/test_verify.py +134 -0
- procesio_cli/agents/procesio/tests/test_workspace_scope.py +97 -0
- procesio_cli/agents/procesio/verifylib.py +222 -0
- procesio_cli/dashboard/README.md +117 -0
- procesio_cli/dashboard/__init__.py +18 -0
- procesio_cli/dashboard/serve.py +98 -0
- procesio_cli/dashboard/server/__init__.py +1 -0
- procesio_cli/dashboard/server/config_schemas.py +92 -0
- procesio_cli/dashboard/server/google.py +103 -0
- procesio_cli/dashboard/server/handler.py +160 -0
- procesio_cli/dashboard/server/inventory.py +213 -0
- procesio_cli/dashboard/server/jobs.py +118 -0
- procesio_cli/dashboard/server/llmtest.py +181 -0
- procesio_cli/dashboard/server/procesio_env.py +94 -0
- procesio_cli/dashboard/server/routes.py +74 -0
- procesio_cli/dashboard/server/runner.py +150 -0
- procesio_cli/dashboard/server/security.py +29 -0
- procesio_cli/dashboard/server/setup.py +211 -0
- procesio_cli/dashboard/server/validate.py +152 -0
- procesio_cli/dashboard/tests/conftest.py +16 -0
- procesio_cli/dashboard/tests/test_dashboard.py +225 -0
- procesio_cli/dashboard/tests/test_procesio_env.py +159 -0
- procesio_cli/dashboard/web/actions.js +274 -0
- procesio_cli/dashboard/web/api.js +79 -0
- procesio_cli/dashboard/web/app.js +385 -0
- procesio_cli/dashboard/web/copilot.js +72 -0
- procesio_cli/dashboard/web/google.js +121 -0
- procesio_cli/dashboard/web/index.html +67 -0
- procesio_cli/dashboard/web/procesio_env.js +187 -0
- procesio_cli/dashboard/web/styles.css +207 -0
- procesio_cli/registry.py +370 -0
- procesio_cli/scripts/build-router.py +249 -0
- procesio_cli/scripts/build-tool-skill.py +202 -0
- procesio_cli/scripts/check-requirements.py +131 -0
- procesio_cli/scripts/check-skill-governance.py +174 -0
- procesio_cli/scripts/evaluate-skill-routing.py +217 -0
- procesio_cli/scripts/evaluate-skills.py +316 -0
- procesio_cli/scripts/get-skill.py +122 -0
- procesio_cli/scripts/list-skills.py +68 -0
- procesio_cli/scripts/list-tools.py +73 -0
- procesio_cli/scripts/run-agent.py +59 -0
- procesio_cli/scripts/run-tool.py +123 -0
- procesio_cli/scripts/secret_scan.py +584 -0
- procesio_cli/scripts/set-credential.py +126 -0
- procesio_cli/scripts/validate-skills.py +530 -0
- procesio_cli/skills/PORTFOLIO.md +134 -0
- procesio_cli/skills/__init__.py +6 -0
- procesio_cli/skills/agent-skill-engineer/SKILL.md +226 -0
- procesio_cli/skills/agent-skill-engineer/evals/evals.json +422 -0
- procesio_cli/skills/agent-skill-engineer/references/authoring-standard.md +178 -0
- procesio_cli/skills/agent-skill-engineer/references/decision-framework.md +107 -0
- procesio_cli/skills/agent-skill-engineer/references/domain-evidence-protocol.md +248 -0
- procesio_cli/skills/agent-skill-engineer/references/evaluation-standard.md +191 -0
- procesio_cli/skills/agent-skill-engineer/references/expert-lenses.md +167 -0
- procesio_cli/skills/agent-skill-engineer/references/field-gate-standard.md +231 -0
- procesio_cli/skills/agent-skill-engineer/references/optimization-protocol.md +233 -0
- procesio_cli/skills/agent-skill-engineer/references/optimizer-contract.md +268 -0
- procesio_cli/skills/agent-skill-engineer/references/portability-standard.md +99 -0
- procesio_cli/skills/agent-skill-engineer/references/research-basis.md +128 -0
- procesio_cli/skills/agent-skill-engineer/references/review-standard.md +143 -0
- procesio_cli/skills/agent-skill-engineer/scripts/audit_skill.py +959 -0
- procesio_cli/skills/agent-skill-engineer/scripts/optimize_skill.py +891 -0
- procesio_cli/skills/agent-skill-engineer/scripts/scaffold_skill.py +397 -0
- procesio_cli/skills/evals/baseline-catalog.json +14 -0
- procesio_cli/skills/evals/baseline-routing-v2.json +38 -0
- procesio_cli/skills/evals/baseline.json +37 -0
- procesio_cli/skills/evals/behavioral.json +367 -0
- procesio_cli/skills/evals/field-boundary-development-v1.json +126 -0
- procesio_cli/skills/evals/field-closeout-correction-development-v1.json +23 -0
- procesio_cli/skills/evals/field-closeout-development-v1.json +89 -0
- procesio_cli/skills/evals/portfolio-pressure-training-v1.json +83 -0
- procesio_cli/skills/evals/routing.json +363 -0
- procesio_cli/skills/evals/validation-baseline.json +4 -0
- procesio_cli/skills/procesio-cli/SKILL.md +134 -0
- procesio_cli/skills/procesio-cli/evals/evals.json +111 -0
- procesio_cli/skills/procesio-cli/evals/workflows.json +16 -0
- procesio_cli/skills/procesio-cli/references/connector-lifecycle.md +47 -0
- procesio_cli/skills/procesio-cli/references/credentials-admin.md +113 -0
- procesio_cli/skills/procesio-cli/references/data-verification.md +71 -0
- procesio_cli/skills/procesio-cli/references/documents-files.md +44 -0
- procesio_cli/skills/procesio-cli/references/form-e2e.md +57 -0
- procesio_cli/skills/procesio-cli/references/operation-contract.md +138 -0
- procesio_cli/skills/procesio-cli/references/process-debugging.md +65 -0
- procesio_cli/skills/procesio-cli/references/process-lifecycle.md +88 -0
- procesio_cli/skills/procesio-cli/references/schedules-webhooks.md +58 -0
- procesio_cli/skills/procesio-cli/references/transport-environments.md +53 -0
- procesio_cli/skills/procesio-cli-maintainer/SKILL.md +84 -0
- procesio_cli/skills/procesio-cli-maintainer/evals/evals.json +116 -0
- procesio_cli/skills/procesio-cli-maintainer/references/change-contract.md +34 -0
- procesio_cli/skills/procesio-cli-maintainer/references/mcp-compatibility.md +13 -0
- procesio_cli/skills/procesio-cli-maintainer/references/skill-authoring.md +51 -0
- procesio_cli/skills/procesio-platform-advisor/SKILL.md +82 -0
- procesio_cli/skills/procesio-platform-advisor/evals/evals.json +116 -0
- procesio_cli/skills/procesio-platform-advisor/references/capability-map.md +22 -0
- procesio_cli/skills/procesio-platform-advisor/references/fit-framework.md +35 -0
- procesio_cli/skills/procesio-platform-advisor/references/freshness-policy.md +25 -0
- procesio_cli/skills/procesio-platform-advisor/references/sizing-method.md +70 -0
- procesio_cli/skills/procesio-platform-advisor/scripts/estimate_capacity.py +99 -0
- procesio_cli/skills/procesio-setup/SKILL.md +180 -0
- procesio_cli/skills/sql-server-optimizer/SKILL.md +86 -0
- procesio_cli/skills/sql-server-optimizer/evals/evals.json +116 -0
- procesio_cli/skills/sql-server-optimizer/references/db-context.md +44 -0
- procesio_cli/skills/sql-server-optimizer/references/generic-mode.md +32 -0
- procesio_cli/skills/sql-server-optimizer/references/procesio-mode.md +40 -0
- procesio_cli/skills/sql-server-optimizer/references/sql-rules.md +43 -0
- procesio_cli/skills/sql-server-optimizer/scripts/export-indexes.sql +178 -0
- procesio_cli/skills/sql-server-optimizer/scripts/export-procs-and-functions.sql +118 -0
- procesio_cli/skills/sql-server-optimizer/scripts/export-tables.sql +367 -0
- procesio_cli/skills/tests/__init__.py +0 -0
- procesio_cli/skills/tests/test_agent_skill_engineer.py +240 -0
- procesio_cli/skills/tests/test_auth_failure_stop.py +25 -0
- procesio_cli/skills/tests/test_capacity_estimator.py +85 -0
- procesio_cli/skills/tests/test_field_boundary_learning.py +100 -0
- procesio_cli/skills/tests/test_field_closeout_learning.py +123 -0
- procesio_cli/skills/tests/test_field_gate_standard.py +76 -0
- procesio_cli/skills/tests/test_operational_playbooks.py +51 -0
- procesio_cli/skills/tests/test_portfolio_pressure_training.py +35 -0
- procesio_cli/skills/tests/test_process_lifecycle_single_run.py +25 -0
- procesio_cli/skills/tests/test_skill_evaluator.py +67 -0
- procesio_cli/skills/tests/test_skill_optimizer.py +473 -0
- procesio_cli/skills/tests/test_skill_portfolio_review.py +70 -0
- procesio_cli/skills/tests/test_skill_release_binding.py +204 -0
- procesio_cli/skills/tests/test_skill_routing.py +74 -0
- procesio_cli/skills/tests/test_skill_scaffold_v2.py +116 -0
- procesio_cli/skills/tests/test_validate_skills.py +115 -0
- procesio_cli/tools/__init__.py +0 -0
- procesio_cli/tools/_lib/README.md +119 -0
- procesio_cli/tools/_lib/__init__.py +0 -0
- procesio_cli/tools/_lib/accounting.py +120 -0
- procesio_cli/tools/_lib/contacts.py +544 -0
- procesio_cli/tools/_lib/creds.py +83 -0
- procesio_cli/tools/_lib/creds_backends.py +578 -0
- procesio_cli/tools/_lib/dbprofiles.py +147 -0
- procesio_cli/tools/_lib/dbquery.py +286 -0
- procesio_cli/tools/_lib/dbschema.py +225 -0
- procesio_cli/tools/_lib/io.py +54 -0
- procesio_cli/tools/_lib/manifest.py +297 -0
- procesio_cli/tools/_lib/skill_release.py +127 -0
- procesio_cli/tools/_lib/skill_resources.py +118 -0
- procesio_cli/tools/_lib/userdata.py +228 -0
- procesio_cli/tools/_lib/webserialize/__init__.py +16 -0
- procesio_cli/tools/_lib/webserialize/admin.py +61 -0
- procesio_cli/tools/_lib/webserialize/client.py +264 -0
- procesio_cli/tools/_lib/webserialize/config.py +96 -0
- procesio_cli/tools/_lib/webserialize/errors.py +27 -0
- procesio_cli/tools/_lib/webserialize/framing.py +45 -0
- procesio_cli/tools/_lib/webserialize/registry.py +47 -0
- procesio_cli/tools/_lib/webserialize/runtime.py +61 -0
- procesio_cli/tools/_lib/webserialize/server.py +510 -0
- procesio_cli/tools/_lib/websession.py +194 -0
- procesio_cli/tools/connector-builder/CONNECTOR-BUILDER-API-NOTES.md +91 -0
- procesio_cli/tools/connector-builder/README.md +101 -0
- procesio_cli/tools/connector-builder/SKILL.md +248 -0
- procesio_cli/tools/connector-builder/__init__.py +7 -0
- procesio_cli/tools/connector-builder/actiondef.py +24 -0
- procesio_cli/tools/connector-builder/client.py +251 -0
- procesio_cli/tools/connector-builder/errors.py +44 -0
- procesio_cli/tools/connector-builder/gen_manifest.py +142 -0
- procesio_cli/tools/connector-builder/handlers/__init__.py +1 -0
- procesio_cli/tools/connector-builder/handlers/admin.py +182 -0
- procesio_cli/tools/connector-builder/handlers/auth.py +74 -0
- procesio_cli/tools/connector-builder/handlers/builds.py +396 -0
- procesio_cli/tools/connector-builder/handlers/common.py +104 -0
- procesio_cli/tools/connector-builder/handlers/files.py +111 -0
- procesio_cli/tools/connector-builder/handlers/raw.py +38 -0
- procesio_cli/tools/connector-builder/handlers/telemetry.py +39 -0
- procesio_cli/tools/connector-builder/main.py +94 -0
- procesio_cli/tools/connector-builder/tests/conftest.py +146 -0
- procesio_cli/tools/connector-builder/tests/test_cb_client.py +86 -0
- procesio_cli/tools/connector-builder/tests/test_cb_dispatch.py +105 -0
- procesio_cli/tools/connector-builder/tests/test_cb_manifest_sync.py +76 -0
- procesio_cli/tools/connector-builder/tests/test_cb_wait.py +123 -0
- procesio_cli/tools/connector-builder/tool.yaml +671 -0
- procesio_cli/tools/framework-map/.gitattributes +2 -0
- procesio_cli/tools/framework-map/README.md +98 -0
- procesio_cli/tools/framework-map/SKILL.md +30 -0
- procesio_cli/tools/framework-map/app.js +188 -0
- procesio_cli/tools/framework-map/fm_builder.py +476 -0
- procesio_cli/tools/framework-map/fm_catalog.py +19 -0
- procesio_cli/tools/framework-map/fm_ro_catalog.py +94 -0
- procesio_cli/tools/framework-map/fm_strings.py +101 -0
- procesio_cli/tools/framework-map/main.py +95 -0
- procesio_cli/tools/framework-map/styles.css +214 -0
- procesio_cli/tools/framework-map/tests/conftest.py +33 -0
- procesio_cli/tools/framework-map/tests/test_fm_build.py +126 -0
- procesio_cli/tools/framework-map/tests/test_fm_manifest_sync.py +63 -0
- procesio_cli/tools/framework-map/tests/test_fm_store_tree.py +75 -0
- procesio_cli/tools/framework-map/tool.yaml +61 -0
- procesio_cli/tools/mysql/MOVED-TO-CENTRAL.md +29 -0
- procesio_cli/tools/mysql/README.md +196 -0
- procesio_cli/tools/mysql/SKILL.md +37 -0
- procesio_cli/tools/mysql/__init__.py +0 -0
- procesio_cli/tools/mysql/connection.py +191 -0
- procesio_cli/tools/mysql/main.py +487 -0
- procesio_cli/tools/mysql/profiles.template.json +1 -0
- procesio_cli/tools/mysql/schema.py +434 -0
- procesio_cli/tools/mysql/tests/__init__.py +0 -0
- procesio_cli/tools/mysql/tests/conftest.py +21 -0
- procesio_cli/tools/mysql/tests/test_manifest_sync.py +68 -0
- procesio_cli/tools/mysql/tests/test_mysql.py +201 -0
- procesio_cli/tools/mysql/tests/test_mysql_schema.py +337 -0
- procesio_cli/tools/mysql/tool.yaml +112 -0
- procesio_cli/tools/procesio/DTO-SUBTOOLS-NOTE.md +360 -0
- procesio_cli/tools/procesio/FORM-DEV-GUIDE/00-INDEX.md +67 -0
- procesio_cli/tools/procesio/FORM-DEV-GUIDE/01-ANATOMY.md +209 -0
- procesio_cli/tools/procesio/FORM-DEV-GUIDE/02-CODE-INJECTION.md +309 -0
- procesio_cli/tools/procesio/FORM-DEV-GUIDE/03-DOM-CONTRACT.md +370 -0
- procesio_cli/tools/procesio/FORM-DEV-GUIDE/04-INTERACTION-RECIPES.md +600 -0
- procesio_cli/tools/procesio/FORM-DEV-GUIDE/05-STEPPER-AND-MOTION.md +426 -0
- procesio_cli/tools/procesio/FORM-DEV-GUIDE/06-PROCESS-INTEGRATION.md +347 -0
- procesio_cli/tools/procesio/FORM-DEV-GUIDE/07-DEPLOY-WORKFLOW.md +294 -0
- procesio_cli/tools/procesio/FORM-DEV-GUIDE/08-PITFALLS.md +569 -0
- procesio_cli/tools/procesio/FORM-DEV-GUIDE/09-NAVIGATION-AND-HOSTING.md +308 -0
- procesio_cli/tools/procesio/PHASE4-E2E-NOTES.md +594 -0
- procesio_cli/tools/procesio/PROCESIO-API-CORRECTIONS.md +295 -0
- procesio_cli/tools/procesio/PROCESIO-API-NOTES.md +6976 -0
- procesio_cli/tools/procesio/PROCESIO-AUTH-NOTES.md +226 -0
- procesio_cli/tools/procesio/PROCESIO-CARD-BUILD-NOTES.md +183 -0
- procesio_cli/tools/procesio/PROCESIO-CONNECTORS-NOTES.md +141 -0
- procesio_cli/tools/procesio/PROCESIO-CUSTOM-ACTION-NOTES.md +179 -0
- procesio_cli/tools/procesio/PROCESIO-DOCS-FIX-REPORT.md +123 -0
- procesio_cli/tools/procesio/PROCESIO-ENVIRONMENTS-NOTES.md +94 -0
- procesio_cli/tools/procesio/PROCESIO-FE-VALIDATION-NOTES.md +107 -0
- procesio_cli/tools/procesio/PROCESIO-FOREACH-NOTES.md +199 -0
- procesio_cli/tools/procesio/PROCESIO-FORM-API-HANG-NOTE.md +101 -0
- procesio_cli/tools/procesio/PROCESIO-FORM-SUBMISSION-NOTES.md +172 -0
- procesio_cli/tools/procesio/PROCESIO-HTML-TO-DOCX-NOTES.md +110 -0
- procesio_cli/tools/procesio/PROCESIO-INSTANCE-HISTORY-NOTES.md +242 -0
- procesio_cli/tools/procesio/PROCESIO-METERING-NOTES.md +201 -0
- procesio_cli/tools/procesio/PROCESIO-NODE-CODE-NOTES.md +279 -0
- procesio_cli/tools/procesio/PROCESIO-NODE-MODULE-WHITELIST.md +113 -0
- procesio_cli/tools/procesio/PROCESIO-PYTHON-ACTION-NOTES.md +165 -0
- procesio_cli/tools/procesio/PROCESIO-QUERY-STORE-NOTES.md +826 -0
- procesio_cli/tools/procesio/PROCESIO-RECONCILIATION-PATTERNS.md +104 -0
- procesio_cli/tools/procesio/PROCESIO-RESOURCE-MODEL-NOTES.md +1100 -0
- procesio_cli/tools/procesio/PROCESIO-SEND-EMAIL-CRED-OPTIONALITY.md +45 -0
- procesio_cli/tools/procesio/PROCESIO-SEND-EMAIL-NOTES.md +252 -0
- procesio_cli/tools/procesio/PROCESIO-SQL-ACTIONS-NOTES.md +284 -0
- procesio_cli/tools/procesio/PROCESIO-USAGE-GUIDE.md +219 -0
- procesio_cli/tools/procesio/README.md +341 -0
- procesio_cli/tools/procesio/SCHEDULE-INPUT-SECURITY-NOTES.md +63 -0
- procesio_cli/tools/procesio/SKILL.md +694 -0
- procesio_cli/tools/procesio/__init__.py +1 -0
- procesio_cli/tools/procesio/actiondef.py +27 -0
- procesio_cli/tools/procesio/assets/html2docx/html2docx.js +2155 -0
- procesio_cli/tools/procesio/auth.py +354 -0
- procesio_cli/tools/procesio/autogen.py +121 -0
- procesio_cli/tools/procesio/client.py +355 -0
- procesio_cli/tools/procesio/config.py +96 -0
- procesio_cli/tools/procesio/data/endpoints.json +2901 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/01-authentication.md +180 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/02-conventions.md +116 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/ANONYMOUS-SURFACE.md +51 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/README.md +104 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/SYMBOL-INDEX.md +444 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/03-auth-users-workspaces.md +731 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/04-processes.md +913 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/05-actions.md +605 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/06-files.md +237 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/07-forms-documents.md +985 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/08-credentials.md +532 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/09-datastore-datatypes.md +830 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/10-custom-urls.md +319 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/11-subscriptions-resources-analytics.md +455 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/12-webhooks-notifications-misc.md +519 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/13-realtime-signalr.md +153 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/99-internal-and-other-services.md +52 -0
- procesio_cli/tools/procesio/docs_info/FormBuilder mock.ts +5725 -0
- procesio_cli/tools/procesio/docs_info/Procesio Platform Actions.json +30219 -0
- procesio_cli/tools/procesio/docs_info/form-config-enums.ts +92 -0
- procesio_cli/tools/procesio/docs_info/form-theme.ts +1603 -0
- procesio_cli/tools/procesio/docs_info/process-validation-reference-1.md +2739 -0
- procesio_cli/tools/procesio/dto/__init__.py +13 -0
- procesio_cli/tools/procesio/dto/credential/builder.py +179 -0
- procesio_cli/tools/procesio/dto/credential/config.schema.json +19 -0
- procesio_cli/tools/procesio/dto/credential/description.md +193 -0
- procesio_cli/tools/procesio/dto/credential/fixtures/rest.config.json +11 -0
- procesio_cli/tools/procesio/dto/credential/fixtures/rest.dto.json +28 -0
- procesio_cli/tools/procesio/dto/credential/fixtures/rest.template.json +44 -0
- procesio_cli/tools/procesio/dto/credential/template.dto.json +16 -0
- procesio_cli/tools/procesio/dto/data/_refresh.py +147 -0
- procesio_cli/tools/procesio/dto/data/action_catalog.json +30825 -0
- procesio_cli/tools/procesio/dto/data/action_families.json +55 -0
- procesio_cli/tools/procesio/dto/data/platform_types.json +182 -0
- procesio_cli/tools/procesio/dto/datatype/builder.py +223 -0
- procesio_cli/tools/procesio/dto/datatype/config.schema.json +47 -0
- procesio_cli/tools/procesio/dto/datatype/description.md +85 -0
- procesio_cli/tools/procesio/dto/datatype/fixtures/customer.config.json +41 -0
- procesio_cli/tools/procesio/dto/datatype/fixtures/customer.dto.json +164 -0
- procesio_cli/tools/procesio/dto/datatype/template.dto.json +37 -0
- procesio_cli/tools/procesio/dto/document/builder.py +193 -0
- procesio_cli/tools/procesio/dto/document/config.schema.json +33 -0
- procesio_cli/tools/procesio/dto/document/description.md +124 -0
- procesio_cli/tools/procesio/dto/document/fixtures/invoice.config.json +16 -0
- procesio_cli/tools/procesio/dto/document/fixtures/invoice.dto.json +32 -0
- procesio_cli/tools/procesio/dto/document/template.dto.json +14 -0
- procesio_cli/tools/procesio/dto/form/FORM-STYLING-NOTES.md +142 -0
- procesio_cli/tools/procesio/dto/form/GOLDEN-DRIFT-NOTES.md +72 -0
- procesio_cli/tools/procesio/dto/form/RUN-PROCESS-RESULT-NOTES.md +80 -0
- procesio_cli/tools/procesio/dto/form/addelement.py +277 -0
- procesio_cli/tools/procesio/dto/form/builder.py +1009 -0
- procesio_cli/tools/procesio/dto/form/capture_goldens.py +106 -0
- procesio_cli/tools/procesio/dto/form/code_cipher.py +67 -0
- procesio_cli/tools/procesio/dto/form/config.schema.json +76 -0
- procesio_cli/tools/procesio/dto/form/data_shell.json +1 -0
- procesio_cli/tools/procesio/dto/form/description.md +346 -0
- procesio_cli/tools/procesio/dto/form/elements/approval.json +259 -0
- procesio_cli/tools/procesio/dto/form/elements/assignee.json +137 -0
- procesio_cli/tools/procesio/dto/form/elements/button.json +125 -0
- procesio_cli/tools/procesio/dto/form/elements/chart.json +341 -0
- procesio_cli/tools/procesio/dto/form/elements/chat.json +199 -0
- procesio_cli/tools/procesio/dto/form/elements/checkbox.json +153 -0
- procesio_cli/tools/procesio/dto/form/elements/column.json +77 -0
- procesio_cli/tools/procesio/dto/form/elements/columns.json +78 -0
- procesio_cli/tools/procesio/dto/form/elements/datetime-input.json +304 -0
- procesio_cli/tools/procesio/dto/form/elements/divider.json +54 -0
- procesio_cli/tools/procesio/dto/form/elements/dropdown.json +130 -0
- procesio_cli/tools/procesio/dto/form/elements/dynamic-table-row.json +253 -0
- procesio_cli/tools/procesio/dto/form/elements/file-upload.json +196 -0
- procesio_cli/tools/procesio/dto/form/elements/file-viewer.json +169 -0
- procesio_cli/tools/procesio/dto/form/elements/heading.json +79 -0
- procesio_cli/tools/procesio/dto/form/elements/icon.json +107 -0
- procesio_cli/tools/procesio/dto/form/elements/image.json +174 -0
- procesio_cli/tools/procesio/dto/form/elements/input.json +206 -0
- procesio_cli/tools/procesio/dto/form/elements/list.json +202 -0
- procesio_cli/tools/procesio/dto/form/elements/number-input.json +202 -0
- procesio_cli/tools/procesio/dto/form/elements/paragraph.json +79 -0
- procesio_cli/tools/procesio/dto/form/elements/radiobox.json +174 -0
- procesio_cli/tools/procesio/dto/form/elements/section.json +114 -0
- procesio_cli/tools/procesio/dto/form/elements/select.json +217 -0
- procesio_cli/tools/procesio/dto/form/elements/side-panel.json +146 -0
- procesio_cli/tools/procesio/dto/form/elements/signature-pad.json +141 -0
- procesio_cli/tools/procesio/dto/form/elements/static-table-row.json +84 -0
- procesio_cli/tools/procesio/dto/form/elements/step.json +105 -0
- procesio_cli/tools/procesio/dto/form/elements/stepper.json +126 -0
- procesio_cli/tools/procesio/dto/form/elements/tab.json +77 -0
- procesio_cli/tools/procesio/dto/form/elements/table.json +279 -0
- procesio_cli/tools/procesio/dto/form/elements/tabs.json +114 -0
- procesio_cli/tools/procesio/dto/form/elements/textarea.json +213 -0
- procesio_cli/tools/procesio/dto/form/enum_map.json +68 -0
- procesio_cli/tools/procesio/dto/form/fieldpath.py +284 -0
- procesio_cli/tools/procesio/dto/form/fixtures/reg.config.json +32 -0
- procesio_cli/tools/procesio/dto/form/fixtures/reg.elements.json +638 -0
- procesio_cli/tools/procesio/dto/form/sync_from_mock.py +386 -0
- procesio_cli/tools/procesio/dto/framework.py +125 -0
- procesio_cli/tools/procesio/dto/process/builder.py +1991 -0
- procesio_cli/tools/procesio/dto/process/config.schema.json +159 -0
- procesio_cli/tools/procesio/dto/process/description.md +218 -0
- procesio_cli/tools/procesio/dto/process/fixtures/greet.config.json +32 -0
- procesio_cli/tools/procesio/dto/process/fixtures/greet.dto.json +317 -0
- procesio_cli/tools/procesio/dto/process/naming.py +305 -0
- procesio_cli/tools/procesio/dto/process/normalize.py +74 -0
- procesio_cli/tools/procesio/dto/process/template.dto.json +32 -0
- procesio_cli/tools/procesio/dto/refdata.py +87 -0
- procesio_cli/tools/procesio/dto/registry.py +27 -0
- procesio_cli/tools/procesio/dto/webhook/builder.py +142 -0
- procesio_cli/tools/procesio/dto/webhook/config.schema.json +25 -0
- procesio_cli/tools/procesio/dto/webhook/description.md +92 -0
- procesio_cli/tools/procesio/dto/webhook/fixtures/order.config.json +10 -0
- procesio_cli/tools/procesio/dto/webhook/fixtures/order.dto.json +25 -0
- procesio_cli/tools/procesio/dto/webhook/template.dto.json +14 -0
- procesio_cli/tools/procesio/environments.py +264 -0
- procesio_cli/tools/procesio/errors.py +166 -0
- procesio_cli/tools/procesio/flowmodel/README.md +37 -0
- procesio_cli/tools/procesio/flowmodel/__init__.py +14 -0
- procesio_cli/tools/procesio/flowmodel/digest.py +223 -0
- procesio_cli/tools/procesio/flowmodel/families.py +34 -0
- procesio_cli/tools/procesio/flowmodel/fevalidation.py +1098 -0
- procesio_cli/tools/procesio/flowmodel/formdigest.py +232 -0
- procesio_cli/tools/procesio/flowmodel/inspect.py +78 -0
- procesio_cli/tools/procesio/flowmodel/model.py +82 -0
- procesio_cli/tools/procesio/flowmodel/nodeparam.py +871 -0
- procesio_cli/tools/procesio/flowmodel/reader.py +191 -0
- procesio_cli/tools/procesio/flowmodel/sqlparam.py +410 -0
- procesio_cli/tools/procesio/form_code_keys.py +50 -0
- procesio_cli/tools/procesio/formlint.py +292 -0
- procesio_cli/tools/procesio/gen_manifest.py +118 -0
- procesio_cli/tools/procesio/handlers/__init__.py +1 -0
- procesio_cli/tools/procesio/handlers/auth_actions.py +103 -0
- procesio_cli/tools/procesio/handlers/catalog.py +147 -0
- procesio_cli/tools/procesio/handlers/common.py +90 -0
- procesio_cli/tools/procesio/handlers/customaction_ops.py +146 -0
- procesio_cli/tools/procesio/handlers/datastore_ops.py +482 -0
- procesio_cli/tools/procesio/handlers/datatype_ops.py +275 -0
- procesio_cli/tools/procesio/handlers/dto_actions.py +258 -0
- procesio_cli/tools/procesio/handlers/environment_admin.py +146 -0
- procesio_cli/tools/procesio/handlers/fevalidate.py +236 -0
- procesio_cli/tools/procesio/handlers/files.py +141 -0
- procesio_cli/tools/procesio/handlers/flowgraph.py +229 -0
- procesio_cli/tools/procesio/handlers/flowlint.py +269 -0
- procesio_cli/tools/procesio/handlers/form_chains.py +336 -0
- procesio_cli/tools/procesio/handlers/form_code.py +277 -0
- procesio_cli/tools/procesio/handlers/form_element.py +199 -0
- procesio_cli/tools/procesio/handlers/form_events.py +441 -0
- procesio_cli/tools/procesio/handlers/form_update.py +270 -0
- procesio_cli/tools/procesio/handlers/formprocess.py +211 -0
- procesio_cli/tools/procesio/handlers/generic.py +135 -0
- procesio_cli/tools/procesio/handlers/layout.py +137 -0
- procesio_cli/tools/procesio/handlers/nodeparams.py +1018 -0
- procesio_cli/tools/procesio/handlers/process_layout.py +189 -0
- procesio_cli/tools/procesio/handlers/process_naming.py +213 -0
- procesio_cli/tools/procesio/handlers/processes.py +416 -0
- procesio_cli/tools/procesio/handlers/profile_admin.py +184 -0
- procesio_cli/tools/procesio/handlers/resource_ops.py +447 -0
- procesio_cli/tools/procesio/handlers/schedules.py +320 -0
- procesio_cli/tools/procesio/handlers/sqlactions.py +232 -0
- procesio_cli/tools/procesio/handlers/transport.py +463 -0
- procesio_cli/tools/procesio/handlers/usageguide.py +222 -0
- procesio_cli/tools/procesio/layout/README.md +196 -0
- procesio_cli/tools/procesio/layout/__init__.py +11 -0
- procesio_cli/tools/procesio/layout/adapter.py +736 -0
- procesio_cli/tools/procesio/layout/cycles.py +186 -0
- procesio_cli/tools/procesio/layout/dispatch.py +39 -0
- procesio_cli/tools/procesio/layout/elk/elk_runner.mjs +50 -0
- procesio_cli/tools/procesio/layout/elk/package-lock.json +21 -0
- procesio_cli/tools/procesio/layout/elk/package.json +11 -0
- procesio_cli/tools/procesio/layout/elk_engine.py +568 -0
- procesio_cli/tools/procesio/layout/engine.py +1311 -0
- procesio_cli/tools/procesio/layout/report.py +187 -0
- procesio_cli/tools/procesio/main.py +179 -0
- procesio_cli/tools/procesio/profiles.py +193 -0
- procesio_cli/tools/procesio/reliability.py +193 -0
- procesio_cli/tools/procesio/sqlformat.py +167 -0
- procesio_cli/tools/procesio/swagger.py +51 -0
- procesio_cli/tools/procesio/tests/__init__.py +0 -0
- procesio_cli/tools/procesio/tests/conftest.py +129 -0
- procesio_cli/tools/procesio/tests/test_auth.py +200 -0
- procesio_cli/tools/procesio/tests/test_autogen.py +78 -0
- procesio_cli/tools/procesio/tests/test_builder_attrpath_sqlbind.py +180 -0
- procesio_cli/tools/procesio/tests/test_builder_custom_action_catalog.py +72 -0
- procesio_cli/tools/procesio/tests/test_client.py +114 -0
- procesio_cli/tools/procesio/tests/test_client_reliability.py +139 -0
- procesio_cli/tools/procesio/tests/test_customaction.py +103 -0
- procesio_cli/tools/procesio/tests/test_customaction_test.py +80 -0
- procesio_cli/tools/procesio/tests/test_cycles.py +69 -0
- procesio_cli/tools/procesio/tests/test_datastore.py +378 -0
- procesio_cli/tools/procesio/tests/test_datastore_node.py +94 -0
- procesio_cli/tools/procesio/tests/test_dispatch.py +170 -0
- procesio_cli/tools/procesio/tests/test_document_page_size.py +19 -0
- procesio_cli/tools/procesio/tests/test_dto.py +734 -0
- procesio_cli/tools/procesio/tests/test_edit_dryrun_preview.py +96 -0
- procesio_cli/tools/procesio/tests/test_elk_layout.py +221 -0
- procesio_cli/tools/procesio/tests/test_environments.py +214 -0
- procesio_cli/tools/procesio/tests/test_fevalidate_gate.py +104 -0
- procesio_cli/tools/procesio/tests/test_fevalidation.py +317 -0
- procesio_cli/tools/procesio/tests/test_fieldpath_variables.py +87 -0
- procesio_cli/tools/procesio/tests/test_files.py +72 -0
- procesio_cli/tools/procesio/tests/test_flow_digest.py +202 -0
- procesio_cli/tools/procesio/tests/test_flowlint.py +114 -0
- procesio_cli/tools/procesio/tests/test_flowmodel.py +158 -0
- procesio_cli/tools/procesio/tests/test_form_add_element.py +256 -0
- procesio_cli/tools/procesio/tests/test_form_approval_gaps.py +319 -0
- procesio_cli/tools/procesio/tests/test_form_auto_names.py +60 -0
- procesio_cli/tools/procesio/tests/test_form_chains.py +217 -0
- procesio_cli/tools/procesio/tests/test_form_code_actions.py +188 -0
- procesio_cli/tools/procesio/tests/test_form_code_keys.py +92 -0
- procesio_cli/tools/procesio/tests/test_form_code_style.py +178 -0
- procesio_cli/tools/procesio/tests/test_form_delete_element.py +99 -0
- procesio_cli/tools/procesio/tests/test_form_element_config.py +141 -0
- procesio_cli/tools/procesio/tests/test_form_event_maps.py +135 -0
- procesio_cli/tools/procesio/tests/test_form_event_ops.py +376 -0
- procesio_cli/tools/procesio/tests/test_form_event_replace.py +86 -0
- procesio_cli/tools/procesio/tests/test_form_events.py +92 -0
- procesio_cli/tools/procesio/tests/test_form_parity.py +171 -0
- procesio_cli/tools/procesio/tests/test_form_select_source.py +74 -0
- procesio_cli/tools/procesio/tests/test_form_sync.py +35 -0
- procesio_cli/tools/procesio/tests/test_form_update.py +133 -0
- procesio_cli/tools/procesio/tests/test_formlint.py +155 -0
- procesio_cli/tools/procesio/tests/test_formlint_css_scope.py +38 -0
- procesio_cli/tools/procesio/tests/test_formlint_field_names.py +83 -0
- procesio_cli/tools/procesio/tests/test_guards.py +110 -0
- procesio_cli/tools/procesio/tests/test_hidden_setting_types.py +39 -0
- procesio_cli/tools/procesio/tests/test_html2docx_asset.py +132 -0
- procesio_cli/tools/procesio/tests/test_key_handle_terminology.py +45 -0
- procesio_cli/tools/procesio/tests/test_layout.py +574 -0
- procesio_cli/tools/procesio/tests/test_layout_report.py +88 -0
- procesio_cli/tools/procesio/tests/test_manifest_sync.py +68 -0
- procesio_cli/tools/procesio/tests/test_nodedelete.py +151 -0
- procesio_cli/tools/procesio/tests/test_nodeparam.py +826 -0
- procesio_cli/tools/procesio/tests/test_normalize.py +70 -0
- procesio_cli/tools/procesio/tests/test_payload_docs.py +86 -0
- procesio_cli/tools/procesio/tests/test_process_action_naming.py +170 -0
- procesio_cli/tools/procesio/tests/test_process_call_api_seed.py +46 -0
- procesio_cli/tools/procesio/tests/test_process_ext.py +373 -0
- procesio_cli/tools/procesio/tests/test_process_invariants.py +183 -0
- procesio_cli/tools/procesio/tests/test_process_layout.py +117 -0
- procesio_cli/tools/procesio/tests/test_process_naming.py +188 -0
- procesio_cli/tools/procesio/tests/test_process_query_store.py +172 -0
- procesio_cli/tools/procesio/tests/test_processinfo_variable.py +56 -0
- procesio_cli/tools/procesio/tests/test_profiles.py +127 -0
- procesio_cli/tools/procesio/tests/test_put_projects.py +41 -0
- procesio_cli/tools/procesio/tests/test_reliability.py +107 -0
- procesio_cli/tools/procesio/tests/test_removal_gate.py +95 -0
- procesio_cli/tools/procesio/tests/test_resource_ops.py +173 -0
- procesio_cli/tools/procesio/tests/test_save_validity.py +207 -0
- procesio_cli/tools/procesio/tests/test_schedule_cron_shape.py +111 -0
- procesio_cli/tools/procesio/tests/test_schedules.py +309 -0
- procesio_cli/tools/procesio/tests/test_sqlconvert.py +234 -0
- procesio_cli/tools/procesio/tests/test_sqlformat.py +83 -0
- procesio_cli/tools/procesio/tests/test_sqlparam.py +187 -0
- procesio_cli/tools/procesio/tests/test_superseded_actions.py +54 -0
- procesio_cli/tools/procesio/tests/test_surgical_concurrency.py +156 -0
- procesio_cli/tools/procesio/tests/test_tier4.py +123 -0
- procesio_cli/tools/procesio/tests/test_transport.py +147 -0
- procesio_cli/tools/procesio/tests/test_transport_data_stores.py +168 -0
- procesio_cli/tools/procesio/tests/test_transport_mapper_repair.py +150 -0
- procesio_cli/tools/procesio/tests/test_transport_webhook_strip.py +253 -0
- procesio_cli/tools/procesio/tests/test_usage_guide.py +96 -0
- procesio_cli/tools/procesio/tool.yaml +12486 -0
- procesio_cli/tools/sqlserver/MOVED-TO-CENTRAL.md +29 -0
- procesio_cli/tools/sqlserver/README.md +192 -0
- procesio_cli/tools/sqlserver/SKILL.md +37 -0
- procesio_cli/tools/sqlserver/SQLSERVER-SCHEMA-NOTES.md +284 -0
- procesio_cli/tools/sqlserver/__init__.py +0 -0
- procesio_cli/tools/sqlserver/connection.py +242 -0
- procesio_cli/tools/sqlserver/main.py +521 -0
- procesio_cli/tools/sqlserver/profiles.template.json +1 -0
- procesio_cli/tools/sqlserver/schema.py +600 -0
- procesio_cli/tools/sqlserver/tests/__init__.py +0 -0
- procesio_cli/tools/sqlserver/tests/conftest.py +21 -0
- procesio_cli/tools/sqlserver/tests/test_connection.py +75 -0
- procesio_cli/tools/sqlserver/tests/test_dbprofiles.py +92 -0
- procesio_cli/tools/sqlserver/tests/test_dbquery.py +220 -0
- procesio_cli/tools/sqlserver/tests/test_manifest_sync.py +68 -0
- procesio_cli/tools/sqlserver/tests/test_sqlserver.py +326 -0
- procesio_cli/tools/sqlserver/tests/test_sqlserver_schema.py +488 -0
- procesio_cli/tools/sqlserver/tool.yaml +123 -0
- procesio_cli/tools/web/README.md +381 -0
- procesio_cli/tools/web/SKILL.md +37 -0
- procesio_cli/tools/web/WEB-AUTOMATION-NOTES.md +277 -0
- procesio_cli/tools/web/__init__.py +21 -0
- procesio_cli/tools/web/actiondef.py +24 -0
- procesio_cli/tools/web/api.py +444 -0
- procesio_cli/tools/web/brokered.py +107 -0
- procesio_cli/tools/web/driver.py +839 -0
- procesio_cli/tools/web/drivercontract.py +44 -0
- procesio_cli/tools/web/errors.py +54 -0
- procesio_cli/tools/web/handlers/__init__.py +1 -0
- procesio_cli/tools/web/handlers/archive.py +367 -0
- procesio_cli/tools/web/handlers/browse.py +182 -0
- procesio_cli/tools/web/handlers/contacts.py +74 -0
- procesio_cli/tools/web/handlers/sessmgmt.py +120 -0
- procesio_cli/tools/web/main.py +128 -0
- procesio_cli/tools/web/sessions.py +253 -0
- procesio_cli/tools/web/steps.py +162 -0
- procesio_cli/tools/web/tests/__init__.py +0 -0
- procesio_cli/tools/web/tests/conftest.py +197 -0
- procesio_cli/tools/web/tests/test_api.py +330 -0
- procesio_cli/tools/web/tests/test_archive.py +190 -0
- procesio_cli/tools/web/tests/test_brokered.py +138 -0
- procesio_cli/tools/web/tests/test_dispatch.py +132 -0
- procesio_cli/tools/web/tests/test_errors.py +60 -0
- procesio_cli/tools/web/tests/test_manifest_sync.py +76 -0
- procesio_cli/tools/web/tests/test_page_contacts.py +68 -0
- procesio_cli/tools/web/tests/test_sessions.py +145 -0
- procesio_cli/tools/web/tests/test_steps.py +210 -0
- procesio_cli/tools/web/tool.yaml +184 -0
- procesio_cli/tools/xlsx/README.md +34 -0
- procesio_cli/tools/xlsx/SKILL.md +28 -0
- procesio_cli/tools/xlsx/__init__.py +0 -0
- procesio_cli/tools/xlsx/main.py +129 -0
- procesio_cli/tools/xlsx/reader.py +91 -0
- procesio_cli/tools/xlsx/tests/__init__.py +0 -0
- procesio_cli/tools/xlsx/tests/conftest.py +39 -0
- procesio_cli/tools/xlsx/tests/test_xlsx.py +103 -0
- procesio_cli/tools/xlsx/tool.yaml +30 -0
- procesio_cli/webplatform/aat_mcp/AAT-MCP-NOTES.md +244 -0
- procesio_cli/webplatform/aat_mcp/README.md +78 -0
- procesio_cli/webplatform/aat_mcp/bridge.py +705 -0
- procesio_cli/webplatform/aat_mcp/chat_server.py +194 -0
- procesio_cli/webplatform/aat_mcp/chat_surface.snapshot.json +668 -0
- procesio_cli/webplatform/aat_mcp/chat_surface.yaml +372 -0
- procesio_cli/webplatform/aat_mcp/gate.py +68 -0
- procesio_cli/webplatform/aat_mcp/http_server.py +139 -0
- procesio_cli/webplatform/aat_mcp/protocol.py +175 -0
- procesio_cli/webplatform/aat_mcp/server.py +306 -0
- procesio_cli/webplatform/aat_mcp/tests/conftest.py +8 -0
- procesio_cli/webplatform/aat_mcp/tests/test_aat_mcp.py +255 -0
- procesio_cli/webplatform/aat_mcp/tests/test_chat_surface.py +247 -0
- procesio_cli/webplatform/aat_mcp/tests/test_discovery.py +489 -0
- procesio_cli/webplatform/aat_mcp/tests/test_multiuser.py +86 -0
- procesio_cli/webplatform/aat_mcp/tests/test_progressive_discovery.py +89 -0
- procesio_cli/webplatform/aat_mcp/tests/test_protocol.py +180 -0
- procesio_cli/webplatform/aat_mcp/tests/test_skill_discovery.py +23 -0
- procesio_cli-0.1.1.dist-info/METADATA +467 -0
- procesio_cli-0.1.1.dist-info/RECORD +647 -0
- procesio_cli-0.1.1.dist-info/WHEEL +4 -0
- procesio_cli-0.1.1.dist-info/entry_points.txt +7 -0
- procesio_cli-0.1.1.dist-info/licenses/LICENSE +201 -0
- procesio_cli-0.1.1.dist-info/licenses/NOTICE +5 -0
|
@@ -0,0 +1,1100 @@
|
|
|
1
|
+
# PROCESIO resource model — the `.procesio` export DTO (reference)
|
|
2
|
+
|
|
3
|
+
What a `.procesio` export bundle actually contains, field by field, across every
|
|
4
|
+
resource type. Derived from analysis of live production `.procesio` exports
|
|
5
|
+
(`docs_info/Exports/`). This is **additive reference** for the tool and agent: it
|
|
6
|
+
documents the shapes the builders read/merge onto. It does not change any builder.
|
|
7
|
+
Auth/export mechanics stay in [PROCESIO-API-NOTES.md](PROCESIO-API-NOTES.md); casing
|
|
8
|
+
rule (live=camelCase, export=PascalCase) applies to everything here.
|
|
9
|
+
|
|
10
|
+
Top-level keys (every bundle): `DataTypes, Credentials, Webhooks, DocumentTemplates,
|
|
11
|
+
Flows, Forms, DataStores, TimeStamp`. `Webhooks` is empty at top level — webhooks live
|
|
12
|
+
inside `Flows[].Webhooks`.
|
|
13
|
+
|
|
14
|
+
⚠ **CORRECTED 2026-09-03: `DataStores` is NOT always empty.** It fills whenever the export
|
|
15
|
+
request NAMES a store (`--data-stores` → `dataStoreIds`), and the store's backing data model
|
|
16
|
+
is exported into `DataTypes` alongside it. Each entry carries **schema only** —
|
|
17
|
+
`Id, Name, Description, Columns[{ColumnId, Name, DataTypeId, IsList, IsPrimaryKey, IsRequired,
|
|
18
|
+
IsSystemColumn}], DataTypeId` — with **no rows key of any kind**, so a store always arrives in
|
|
19
|
+
the target EMPTY. The system columns are omitted from the exported `Columns` and re-appended by
|
|
20
|
+
the target on create. Full measurement in
|
|
21
|
+
[PROCESIO-API-NOTES.md](PROCESIO-API-NOTES.md) (dated Data Store section).
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 1. The canvas / flow graph (load-bearing for any layout work)
|
|
26
|
+
|
|
27
|
+
A flow's diagram is a **nested directed graph**. Nodes = `Flows[].Actions[]`; edges =
|
|
28
|
+
each action's `Ports[]`. There is no separate node/edge table — geometry and topology
|
|
29
|
+
live on the actions.
|
|
30
|
+
|
|
31
|
+
### Node geometry — `Action.CustomData`
|
|
32
|
+
```
|
|
33
|
+
CustomData = {
|
|
34
|
+
type: "square" | "diamond" | "circle" | "area",
|
|
35
|
+
name, description, icon,
|
|
36
|
+
position: { x, y }, // canvas coords, top-left of the node
|
|
37
|
+
areaSize: { width, height, x, y }, // 48x48 for normal nodes; real WxH for "area"
|
|
38
|
+
inputPorts: int, outputPorts: int, // port counts (drive validation 390/391)
|
|
39
|
+
configuration: [ { id, label, settings:[...] } ], // designer mirror of Parameters
|
|
40
|
+
wasDropped: bool
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
- **`type` is dictated by the action, not chosen at placement.** Each action template
|
|
44
|
+
carries its shape: `square` = standard action, `diamond` = a branching action
|
|
45
|
+
(Decisional), `circle` = a terminal (Start/Stop), `area` = a container frame. A
|
|
46
|
+
builder or layout tool **inherits this from the action config and must never change
|
|
47
|
+
the shape** when it places or moves a node — only the `position` (and an area's
|
|
48
|
+
`areaSize`) is the tool's to set.
|
|
49
|
+
- Terminals: **Start** = `in0/out1` (the single source); **Stop** = `in1/out0`. A flow
|
|
50
|
+
has one Start and may have several Stops. Normal nodes are 48x48.
|
|
51
|
+
|
|
52
|
+
### Edges — `Action.Ports[]`
|
|
53
|
+
```
|
|
54
|
+
Port = { Id, FlowId, SourceId, DestinationId, Type, State, Data:{}, Errors:{}, Config:{} }
|
|
55
|
+
```
|
|
56
|
+
- `SourceId` / `DestinationId` are **action Ids** (not port ids). A port stored on an
|
|
57
|
+
action represents an edge leaving/entering the flow graph; iterate every action's
|
|
58
|
+
`Ports[]` to get the full edge set.
|
|
59
|
+
- **`Type`**: `0` = normal flow edge, `1` = **error-port** edge. The error port is how
|
|
60
|
+
"on failure go here" is wired (best-practices §5 global try/catch).
|
|
61
|
+
- A **Decisional** (diamond) fans out **any number of normal (Type 0) edges**, one per
|
|
62
|
+
case — there is no branch limit. Branches do **not** have to re-converge: a branch can
|
|
63
|
+
run to a `Stop`, or several branches can merge at one or more `Join` actions at
|
|
64
|
+
different points. A `Join` is the explicit merge point when paths should reunite.
|
|
65
|
+
|
|
66
|
+
### Containment / nesting — `Action.ParentId` + `area` nodes
|
|
67
|
+
An `area` node is a **frame that contains other actions**; the contained actions carry a
|
|
68
|
+
`ParentId` pointing at that area, and are drawn inside its `areaSize` rectangle.
|
|
69
|
+
- The container in active use is the **`For Each` loop body**: a `For Each` action
|
|
70
|
+
renders as an area frame (`CustomData.name == "For Each"`, icon `loop`) and the actions
|
|
71
|
+
it iterates over are parented to it.
|
|
72
|
+
- **A `For Each` cannot contain another `For Each`.** To nest a loop, put a
|
|
73
|
+
`Call Subprocess` (or `Trigger Subprocess`) inside the `For Each` and place the inner
|
|
74
|
+
`For Each` in that subprocess.
|
|
75
|
+
- The Process Designer currently supports **only the `For Each` area** as a container —
|
|
76
|
+
it does not yet work with other/free-form areas. Treat `area` containment as For-Each
|
|
77
|
+
containment for now.
|
|
78
|
+
|
|
79
|
+
So layout is **hierarchical**: lay out a container's children within the container's
|
|
80
|
+
box, size the box to fit, then place the box at the parent level. `areaSize` on an
|
|
81
|
+
area node is the frame rectangle.
|
|
82
|
+
|
|
83
|
+
### Viewport — `Flow.CanvasData`
|
|
84
|
+
`{x, y, zoom}` (e.g. `{0,0,1}`) — the pan/zoom of the designer viewport. **Not** node
|
|
85
|
+
positions. A re-layout tool rewrites each `Action.CustomData.position` and may reset
|
|
86
|
+
`CanvasData` to `{0,0,1}`; it never needs anything else for geometry.
|
|
87
|
+
|
|
88
|
+
### Cross-process edges (the Resource Map graph)
|
|
89
|
+
A process calls another via a **`Call Subprocess`** (synchronous) or
|
|
90
|
+
**`Trigger Subprocess`** (async) action. The target flow id is the action's config
|
|
91
|
+
setting `type:"flow-list"` `value` (a flow GUID). Input mapping is a
|
|
92
|
+
`type:"process-inputs"` setting holding `[{ id, subprocess:<subVarId>, process:<parentVarId> }]`.
|
|
93
|
+
Build the process→process dependency graph by scanning these settings — that is the
|
|
94
|
+
input to the Resource-Map (LVL-1/LVL0/LVL+n) layout.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## 2. Action catalog — common actions by family
|
|
99
|
+
|
|
100
|
+
`Action.Category` is `"cat1"` (a UI bucket, not a useful classifier). The actions a
|
|
101
|
+
builder reaches for most, grouped by what they do (the full per-action config schema is
|
|
102
|
+
the golden `docs_info/Procesio Platform Actions.json`):
|
|
103
|
+
|
|
104
|
+
- **Control / flow:** `Start`, `Stop`, `Decisional` (branch), `Join` (merge),
|
|
105
|
+
`For Each` (loop), `Delay`, `Throw` (raise a controlled error into the error port).
|
|
106
|
+
- **Subprocess:** `Call Subprocess` (run another process synchronously, map vars),
|
|
107
|
+
`Trigger Subprocess` (async fire-and-forget).
|
|
108
|
+
- **Scripting:** `Node` (NodeJS — raw output; needs Timeout>0), `Javascript` (JS — wraps
|
|
109
|
+
output `{result:v}`), `Python`. (Output-wrapping differences: see PROCESIO-API-NOTES.)
|
|
110
|
+
- **Data shaping:** `Map Data`, `Extract Objects`, `Extract List`, `Extract Object`,
|
|
111
|
+
`Extract Text`, `String To JSON`, `Object To String`, `Object To File`, `Get Element`,
|
|
112
|
+
`Has Elements`, `List Keys`, `Length`, `Trim`, `Concatenate`, `Replace`,
|
|
113
|
+
`RegEx Replace`, `Add`.
|
|
114
|
+
- **Integration:** `Call API` (REST), `Execute Query` (SQL SELECT; V1/V2 variants),
|
|
115
|
+
`Execute Command` (SQL non-query; V1 variant), `Send Email` (SMTP — see
|
|
116
|
+
PROCESIO-SEND-EMAIL-NOTES).
|
|
117
|
+
- **Date/time & id:** `UTC Now`, `Today`, `Format DateTime`, `Update DateTime`,
|
|
118
|
+
`Generate GUID`.
|
|
119
|
+
- **Files / Excel:** `Upload File`, `Get File Data`, `Move File v1`, `Create Folder`,
|
|
120
|
+
`Read Range`, `Get Last Used Row`, `Export To XLSX`.
|
|
121
|
+
- **Documents:** `Generate Document` (renders a document template — §5).
|
|
122
|
+
|
|
123
|
+
Icons (for renderers): `icon-stop, icon-start, call_split` (decisional), `icon-join,
|
|
124
|
+
icon-nodejs, icon-call_api, icon-mssql` (SQL), `icon-json, icon-workflow` (subprocess),
|
|
125
|
+
`loop` (For Each), `find_replace, send` (email), `code` (JS), `settings_applications`
|
|
126
|
+
(Map Data).
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## 3. Credentials — `Credentials[]`
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
Credential = { name, tname, type, gid, gtid, gtpid, status,
|
|
134
|
+
properties: [ { id, value }, ... ] }
|
|
135
|
+
```
|
|
136
|
+
- **`gid`** = the credential **instance** id. **`gtid`/`gtpid`** = the credential
|
|
137
|
+
**template** id (the *type*: SQL Server, SMTP, REST API key, Azure GPT, …).
|
|
138
|
+
- `properties[]` = the filled fields, each `{id, value}` where `id` is the template's
|
|
139
|
+
property-definition id. Different credential types have different property sets. A
|
|
140
|
+
property value can itself be a GUID pointing at **another credential** (chained
|
|
141
|
+
credentials — e.g. an LLM credential referencing a key credential).
|
|
142
|
+
- `status` (bool) = tested/enabled state. Secrets are excluded when exported with
|
|
143
|
+
`exportSensitiveData:false`.
|
|
144
|
+
|
|
145
|
+
**How an action uses a credential.** The action's `CustomData.configuration[].settings[]`
|
|
146
|
+
contains a setting of `type:"credentials"` with `credentialsTemplateId` = the template
|
|
147
|
+
(matches the credential's `gtid`) and `value` = the credential **instance `gid`**. Real
|
|
148
|
+
shape — an `Execute Query` action: `{label:"Select Database Server", type:"credentials",
|
|
149
|
+
credentialsTemplateId:"<template guid>", value:"<credential instance gid>"}`. So: pick a
|
|
150
|
+
credential by template, bind the instance gid into the action setting. Never put the
|
|
151
|
+
secret in the process — only the gid reference (best-practices §2 holds).
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## 4. Webhooks — `Flows[].Webhooks[]` (embedded, not a top-level section)
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
Webhook = { Id, WebhookId, IsObsoleted,
|
|
159
|
+
WebhookVariables: [ { VariableId, VariableType } ],
|
|
160
|
+
FilterRules: { Value:[], Parameters:[] } }
|
|
161
|
+
```
|
|
162
|
+
A webhook is **attached to a flow** and binds the flow's **process variables** to
|
|
163
|
+
incoming request parts via `WebhookVariables` (`VariableType` enumerates where the value
|
|
164
|
+
comes from — body/header/query). `FilterRules` gates which requests trigger the run
|
|
165
|
+
(empty = accept all). The webhook URL/secret is referenced by `WebhookId` (the standalone
|
|
166
|
+
webhook resource), not stored inline. Webhook-launched runs are async (launch returns
|
|
167
|
+
empty 200 — playbook §D). The whole body binds to a model-typed variable, not per-field
|
|
168
|
+
(PHASE4-E2E 1).
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## 5. Document templates — `DocumentTemplates[]`
|
|
173
|
+
|
|
174
|
+
```
|
|
175
|
+
DocumentTemplate = { id, name, description,
|
|
176
|
+
body: "<html… escaped, may embed base64 images>",
|
|
177
|
+
placeholderDelimiterStart: "<%", placeholderDelimiterStop: "%>",
|
|
178
|
+
documentPageSize: "A4", documentPageOrientation: 0,
|
|
179
|
+
variables: [ { id, dataType, type, name, defaultValue, isList, isInput, isOutput } ] }
|
|
180
|
+
```
|
|
181
|
+
A document is an **HTML body with `<% %>` placeholders** bound to **typed `variables`**.
|
|
182
|
+
`isList:true` variables drive **repeating tables**; `dataType` is the data-model id, so a
|
|
183
|
+
placeholder can be a typed scalar or a typed list. Page size + orientation are
|
|
184
|
+
configurable. This is what the `Generate Document` action renders: it has a file output
|
|
185
|
+
(**Document Output**) AND an **HTML string** output (direction OUTPUT) — see
|
|
186
|
+
PROCESIO-API-NOTES "Generate Document HTML string". Bind doc variables by **name** in
|
|
187
|
+
docMap (builder resolves name→id), and build the backing data model via the
|
|
188
|
+
attribute-endpoint create flow so it COMPILES (else placeholders render "Unknown").
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## 6. Forms — `Forms[]` (the forms-designer model)
|
|
193
|
+
|
|
194
|
+
```
|
|
195
|
+
Form (outer) = { Id, Name, IsPrivate, Type, Status, State, Assignees:[], Data,
|
|
196
|
+
CustomUrl, WorkspaceName, workspaceId, created*/updated* }
|
|
197
|
+
```
|
|
198
|
+
- **`Type`**: `1` = standard form; `0` = the other variant. **`Status`**: `1` =
|
|
199
|
+
active/published, `0` = draft (per API notes). **`Assignees`** non-empty = a **task /
|
|
200
|
+
approval form** routed to specific users.
|
|
201
|
+
- A single `.procesio` export can be just one form or a form alongside its flows.
|
|
202
|
+
|
|
203
|
+
### `Form.Data` (stringified JSON in the export; object once parsed)
|
|
204
|
+
```
|
|
205
|
+
Data = { browserTitle, elements:[…], valueMap:{}, code:"<encrypted>", images:{},
|
|
206
|
+
hideBranding, messages:[…], dataModel:{…}, variables:[…], events:[…],
|
|
207
|
+
theme:[…], dataModelAttributeFormatVersion, notification, chainConfig:{…} }
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
**Controls — `Data.elements[]`** (flat list, nested via `parentId`). Each element =
|
|
211
|
+
`{ id, category, type, configs:[…], parentId, section, hidden }`. The control catalog
|
|
212
|
+
seen in production, by family:
|
|
213
|
+
|
|
214
|
+
- Layout: `section`, `columns`/`column`, `tabs`/`tab`, `divider`, `side-panel`.
|
|
215
|
+
- Display: `paragraph`, `heading`, `image`, `icon`, `file-viewer`, `chart`.
|
|
216
|
+
- Input: `input`, `textarea`, `number-input`, `datetime-input`, `select`, `dropdown`,
|
|
217
|
+
`checkbox`, `radiobox`, `file-upload`.
|
|
218
|
+
- Data: `table` with `dynamic-table-row` / `static-table-row`, `list`.
|
|
219
|
+
- Action: `button`, **`approval`**.
|
|
220
|
+
|
|
221
|
+
Containment uses `parentId` exactly like the canvas (section/column/tab hold children).
|
|
222
|
+
|
|
223
|
+
**Per-control config — `configs[]`.** Each entry =
|
|
224
|
+
`{ id, key, label, type, value, category, subCategory, exposed, events? }`. The control's
|
|
225
|
+
behavior is spread across these settings. Common keys: `name, id, visible, label,
|
|
226
|
+
tooltip, style, info-text, readonly, value, required, defaultValue, placeholder, regex,
|
|
227
|
+
disabled, sourceType, sourceValue, submit, disabledIfFormIsInvalid, multiple, searchable,
|
|
228
|
+
clearable, rows`, table keys (`hasHeader, hasIndexColumn, tableColumnsSourceType/Value,
|
|
229
|
+
canAdd, canRemove, hasPagination, countPerPage, totalItemsCount`), and the **event keys**
|
|
230
|
+
below.
|
|
231
|
+
|
|
232
|
+
**Data-source binding — `sourceType` / `sourceValue`** (for select/table/list options):
|
|
233
|
+
`JSON` (a static JSON array literal in `sourceValue`), `static-list`, `URL` (fetch options
|
|
234
|
+
from a URL), or `None`. Process-driven option data arrives instead by a RUN_PROCESS event
|
|
235
|
+
writing into the field (below).
|
|
236
|
+
|
|
237
|
+
**Validation / conditional**: `required`, `regex` (e.g. email pattern), `readonly`,
|
|
238
|
+
`disabledIfFormIsInvalid` (enable only when all required are valid — the AAT_ "email me"
|
|
239
|
+
pattern in best-practices), and **`visibility`** rules like
|
|
240
|
+
`{type:"task-assignees", users:null}` (show a field only to the task's assignees — part
|
|
241
|
+
of the approval mechanism).
|
|
242
|
+
|
|
243
|
+
### Events — three layers
|
|
244
|
+
1. **Form lifecycle — `Data.events[]`**: `FORM_LOAD` and `FORM_SUBMIT`. Fire on render /
|
|
245
|
+
on submit.
|
|
246
|
+
2. **Per-control runtime events** live in config keys: `onClickEvents`, `onInputEvents`,
|
|
247
|
+
`onFocusEvents`, `onBlurEvents`, `onTableRowAddedEvents`, `onTableRowDeletedEvents`,
|
|
248
|
+
`onPaginationChangedEvents`. Each holds a list of event objects:
|
|
249
|
+
```
|
|
250
|
+
{ id, type: "CLICK"|"INPUT"|"TABLE_PAGINATED"|"TABLE_ROW_ADDED"|…, // trigger
|
|
251
|
+
action: "RUN_PROCESS" | "RUN_JAVASCRIPT", // what runs
|
|
252
|
+
config: {…} }
|
|
253
|
+
```
|
|
254
|
+
3. **Designer-time events** (e.g. `"EMIT_ELEMENTS_UPDATE"` on a `name` config) — editor
|
|
255
|
+
plumbing, not runtime behavior.
|
|
256
|
+
|
|
257
|
+
**`action:"RUN_PROCESS"` config** (how a form calls a process — extends the memory note):
|
|
258
|
+
```
|
|
259
|
+
config = { syncRun: bool, processId: "<flow guid>",
|
|
260
|
+
inputMap: [ { id, left:"<PROCESS var GUID>", right:"<form value-path>" } ],
|
|
261
|
+
outputMap: [ { id, left:"<form field path>", right:"<process out var path>" } ] }
|
|
262
|
+
```
|
|
263
|
+
- **`syncRun`** chooses synchronous (wait, fill outputs) vs async fire-and-forget.
|
|
264
|
+
- The **process variable GUID is on the LEFT** in BOTH maps; the form value-path on the
|
|
265
|
+
RIGHT (4-part `elementId.dataModelId.attrId.valueConfigId`). A name or form-path on
|
|
266
|
+
the left = the designer can't render it and the launch 400s. The builder resolves this
|
|
267
|
+
(prepare_ctx); guarded by `test_form_parity.py`.
|
|
268
|
+
- Triggers that can drive RUN_PROCESS: `CLICK` (button), `INPUT` (live field change),
|
|
269
|
+
`TABLE_PAGINATED` (server-side paging), `TABLE_ROW_ADDED`, etc.
|
|
270
|
+
|
|
271
|
+
**`action:"RUN_JAVASCRIPT"` config**: `{ code:"<js>" }`. Runs in the form's
|
|
272
|
+
`iframe.trigger-sandbox`; reach the page via `window.parent.document` (e.g. toggling a
|
|
273
|
+
custom loader's `display`). The custom CSS/JS authored in the designer lives in
|
|
274
|
+
**`Data.code`, AES-encrypted** (the value starts with `U2FsdGVkX1…` = OpenSSL/CryptoJS
|
|
275
|
+
`Salted__` — key in Credential Manager; see `dto/form/FORM-STYLING-NOTES.md`). Inline
|
|
276
|
+
event `code` (above) is stored in clear inside the event config.
|
|
277
|
+
|
|
278
|
+
### Styling — `Data.theme[]`
|
|
279
|
+
A list of **CSS-variable sections**: each `{label, properties:[{label, value, cssVariable,
|
|
280
|
+
type}]}`. E.g. section "Colors" → `--c-primary`, `--c-primary-variant`, `--c-on-primary`,
|
|
281
|
+
`--c-error`, `--c-on-error`, … `type:"css-color-preview"`. The sections cover the theme
|
|
282
|
+
(Colors, Typography, etc.). So form styling = setting CSS-variable values per section;
|
|
283
|
+
custom overrides go in `Data.code`. Never force a font on `#app *` (breaks Material-Icons
|
|
284
|
+
glyphs).
|
|
285
|
+
|
|
286
|
+
### Approval — the `approval` control + task routing
|
|
287
|
+
The `approval` control's `configs` carry the approval model:
|
|
288
|
+
- **`approver`** (`type:"user-select"`, value = a user GUID) — the designated approver.
|
|
289
|
+
- **`approverReplacement`** (`type:"approver-replacement"`, value = list of user GUIDs)
|
|
290
|
+
— fallback approvers.
|
|
291
|
+
- Captured outcome: **`response`**, **`comment`**, **`responseDate`**, **`responseUser`**,
|
|
292
|
+
**`approved`** (hidden, filled at runtime).
|
|
293
|
+
- Multi-step: a table-level **`approvalSteps`** key sequences several approvals.
|
|
294
|
+
- Task routing at form level: outer `Assignees` + `Type`, plus per-field
|
|
295
|
+
`assignee`/`assigneeReplacement` configs and the `visibility:{type:"task-assignees"}`
|
|
296
|
+
rule. So an approval flow = assign the form/step to users, show the right fields to
|
|
297
|
+
assignees, capture approve/reject + comment, and branch the downstream process on the
|
|
298
|
+
result.
|
|
299
|
+
|
|
300
|
+
### Multi-form "apps" — `Data.chainConfig`
|
|
301
|
+
`{columns:[…]}` describes a **dashboard of linked forms/tiles** arranged in columns — the
|
|
302
|
+
"App" concept (e.g. an Overview / Production-Dashboard / Marketplace landing page). This
|
|
303
|
+
is how several forms are composed into one navigable application.
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
## What is genuinely new here (vs prior notes)
|
|
308
|
+
|
|
309
|
+
Prior notes already cover: export/import mechanics, casing, validation oracles,
|
|
310
|
+
scripting-action output wrapping, Send Email, scheduler, Generate Document HTML string,
|
|
311
|
+
RUN_PROCESS map orientation, form CSS/JS encryption. **New in this file:** the canvas
|
|
312
|
+
geometry/edge/containment model (positions, action-dictated node shape, `area` =
|
|
313
|
+
For-Each container, `ParentId`, `Type` 0/1 edges, unlimited decisional fan-out), the
|
|
314
|
+
action catalog by family, the credential template-vs-instance model + action binding, the
|
|
315
|
+
webhook embed shape, the document-template DTO, the forms control catalog + config-key
|
|
316
|
+
inventory, the three-layer event model with the RUN_PROCESS/RUN_JAVASCRIPT config shapes,
|
|
317
|
+
`sourceType` data binding, the theme CSS-variable structure, the approval-control model,
|
|
318
|
+
and `chainConfig` apps. None of this changes a builder; it documents what the builders
|
|
319
|
+
read.
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
## These capabilities are CURATED ACTIONS — do not reimplement
|
|
323
|
+
Everything described above is reachable through a runnable action (run `python scripts/run-tool.py procesio`
|
|
324
|
+
to list all ~330). In particular:
|
|
325
|
+
- Parse a flow/export into a node/edge graph → **`read-flow-graph`**; structural summary/smells → **`inspect-flow`**.
|
|
326
|
+
- Auto-layout a canvas (legacy or `LAYOUT_ENGINE=elk`) → **`layout-flow`**; verify positions → **`verify-layout`**;
|
|
327
|
+
cross-process map → **`layout-resource-map`**; re-lay-out a LIVE process in place → **`relayout-process`**.
|
|
328
|
+
- Duplicate a process → **`duplicate-process`**; validate one → **`process-validate`**; delete → **`process-delete`**.
|
|
329
|
+
Reach for the action first; only drop to a raw `<method>-<path>` wrapper or `request` if no curated action fits.
|
|
330
|
+
|
|
331
|
+
---
|
|
332
|
+
|
|
333
|
+
## Editing a flow via API: runtime is `parameters[].value`, NOT the setting (CRITICAL)
|
|
334
|
+
|
|
335
|
+
`PUT /api/Projects` persists what you send but does NOT recompile
|
|
336
|
+
`action.parameters[]` from `action.customData.configuration[].settings[]`. The
|
|
337
|
+
**runtime executes `parameters[].value`**; the setting is only the designer/UI copy.
|
|
338
|
+
Edit one without the other and the canvas shows new logic while the flow runs the old
|
|
339
|
+
one (validation passes regardless). Linkage: `parameters[i].tabPropertyId == settings[j].id`.
|
|
340
|
+
|
|
341
|
+
- Code nodes (`code-editor`): setting.value == param.value (same raw-JS form) → copy
|
|
342
|
+
setting→param for the matching tabPropertyId.
|
|
343
|
+
- SQL nodes (`Execute Query`/`Command`): SQL is a nested `side-pannel` → `Query`
|
|
344
|
+
sub-setting. **Setting uses GUID var refs `N'<guid>'`; param uses positional `<%N%>`.**
|
|
345
|
+
Different syntaxes — edit the param's positional SQL directly; never copy setting→param.
|
|
346
|
+
- datatype/credentials/variable-binding params legitimately hold `<%N%>` while the setting
|
|
347
|
+
holds a 36-char GUID — never sync those.
|
|
348
|
+
|
|
349
|
+
Helper `work/networky/migrations/flowpatch.py`: `setscript` now updates the linked param;
|
|
350
|
+
`syncparams` bulk-syncs code-editor params. (Discovered 2026-07 during the Networky
|
|
351
|
+
overhaul: a swapped router prompt kept emitting the old canned refusal because the old
|
|
352
|
+
code was still in `parameters[].value`.)
|
|
353
|
+
|
|
354
|
+
---
|
|
355
|
+
|
|
356
|
+
## Hand-building a multi-node flow: node-shape recipes (from the Send Contact Card build, 2026-07)
|
|
357
|
+
|
|
358
|
+
Building a new subprocess by **duplicate + surgically transform the DTO in Python** is the
|
|
359
|
+
safest path (every id/port/param stays internally consistent). Duplicating keeps the source's
|
|
360
|
+
variable + action ids — fine, they're only referenced within the one flow. Recipes proven live:
|
|
361
|
+
|
|
362
|
+
- **Graph = `ports[]`.** Each `action.ports[i]` = `{sourceId, destinationId, type:0, state:1,
|
|
363
|
+
data:{}}`. A `Start` node also has an *entry* port `{sourceId:"0000…", destinationId:StartId}` —
|
|
364
|
+
keep it. A **Decisional** emits one port per case + one default port
|
|
365
|
+
(`data:{"isDefault":"default"}`). A **`Stop` takes exactly ONE input port** — if two branches
|
|
366
|
+
both end, you need **two Stop nodes** (validate error 383 "Action has too many input ports").
|
|
367
|
+
|
|
368
|
+
- **Decisional operators:** only `EQUALS / IS_EMPTY / IS_NOT_EMPTY / IS_TRUE / IS_FALSE` are
|
|
369
|
+
reliable in this workspace. Numeric `LESS_THAN` / `GREATER_THAN_OR_EQUAL` **throw at validate**
|
|
370
|
+
("Decisional action: … Exception was thrown"). For an HTTP-status gate use `Status EQUALS "200"`
|
|
371
|
+
(WhatsApp/most Cloud APIs return 200 on success) as the success case, default → error branch.
|
|
372
|
+
Dual form: `parameters[].value` = `[{id, actionid, condition:[{operator, logicOperator,
|
|
373
|
+
leftOperator:{value:"<%0%>", variable:[…]}, rightOperator:{value:"200", variable:[]}}]}]` and
|
|
374
|
+
a separate default param `{value: <targetActionId>}`; `customData…decisional-case` mirrors it
|
|
375
|
+
with GUID refs in `leftOperator.value` (+ a `decisional-default` setting). Template
|
|
376
|
+
`f5dcbb04-253d-4061-99a1-9b2822c2e6d2`, case tabProperty `11d4044a-…f30`, default `…f45`.
|
|
377
|
+
|
|
378
|
+
- **Execute Query node** (template `a9f851c2-e0ba-4fee-9a06-5445ba000001`): credential setting
|
|
379
|
+
`…bc000011` (DB credential, e.g. `45a1dd18` "Database"), a `side-pannel` `…bc000012` holding
|
|
380
|
+
`Query` (code-editor, `…bc000014`), `Timeout` (`…bc000015`), `Output` (type "any", isList true,
|
|
381
|
+
direction 3, `…bc000013`). SQL setting uses `N'<guid>'` var refs; **param uses `N'<%N%>'`** with
|
|
382
|
+
a `variable[]` map — different syntaxes, never copy setting→param for SQL.
|
|
383
|
+
|
|
384
|
+
- **Node (NodeJS)** setting ids are per-instance: Code `code-editor`, Timeout, Single Result
|
|
385
|
+
(`datatype`, dir 3), List Result (`datatype`, isList, dir 3), Error (`datatype`, dir 3). Output
|
|
386
|
+
goes to whichever var the Single Result value points at (its own type governs; the setting's
|
|
387
|
+
`dataTypeId` is decorative). Injection convention: an **object/list** var → bare `let x = <%0%>;`
|
|
388
|
+
(NOT in backticks — backticks corrupt JSON); a **string** var → `` `<%1%>` `` in backticks.
|
|
389
|
+
|
|
390
|
+
- **Call Subprocess** (template `c37e56fe-d924-4604-a86f-7c93f863fcdf`): `Select Subprocess`
|
|
391
|
+
(`bc93d0be-…`) = child flow id; inputs (`process-inputs`, `62cdd318-…`) = list of
|
|
392
|
+
`{subprocess:<child input var id>, process:<parent var id>}` — child var on the LEFT.
|
|
393
|
+
- **The target subprocess MUST be `active:true`** or the parent's `validate` returns
|
|
394
|
+
504 "Called suprocess is not valid… Target flow is inactive". A working callable
|
|
395
|
+
subprocess is `active:true, status:0` (draft-status is fine; *inactive* is not).
|
|
396
|
+
`process-toggle-activation` (PATCH …/toggle-activation) only arms/disarms triggers —
|
|
397
|
+
it does **NOT** flip `active`. To publish for call, set `active:true` on the flow DTO
|
|
398
|
+
and PUT it (`flowpatch put`), then re-fetch to confirm. (Networky Send Contact Card
|
|
399
|
+
wire-up, 2026-07.)
|
|
400
|
+
|
|
401
|
+
- **Call API whole-body injection:** the RAW body value can be a **single `<%0%>`** bound to a
|
|
402
|
+
**string/Text-typed** var whose content is the full JSON (proven by `Chat Flow/Call LLM Fast`:
|
|
403
|
+
RAW body `<%0%>` bound to a Text `Payload`). So a Node can `JSON.stringify(body)` → a Text var →
|
|
404
|
+
Call API posts it verbatim. If a live run ever shows double-encoding, switch the var to Object
|
|
405
|
+
and `return body` (object) from the Node instead.
|
|
406
|
+
|
|
407
|
+
- **Variable PUT schema:** `{id, contextId:null, dataType, type, name, defaultValue:null, isList,
|
|
408
|
+
isError:false, isRequired}`. `type` 10=input, 20=output/local, 40=ProcessInfo. Common dataTypes:
|
|
409
|
+
`…121214` string, `…121211` number, `…121210` bool, `…121220` text/JSON-string, `…121221`
|
|
410
|
+
object, `…121222` uniqueidentifier.
|
|
411
|
+
|
|
412
|
+
Networky flow ids: `Send Contact Card` = `cd3d9bad-45e9-4f05-99f3-fcb86936c0e8` (native
|
|
413
|
+
WhatsApp `type:"contacts"` card; inputs SessionId+UserPhone). Report:
|
|
414
|
+
`work/networky/migrations/reports/vcard-subprocess.md`.
|
|
415
|
+
|
|
416
|
+
---
|
|
417
|
+
|
|
418
|
+
## Node/Call-API/generic-passthrough gotchas (from the Networky DB-wire build, 2026-07)
|
|
419
|
+
|
|
420
|
+
Five non-obvious PROCESIO behaviors that each silently broke a live flow. All cross-cutting.
|
|
421
|
+
|
|
422
|
+
- **`<%N%>` substitutes inside COMMENTS too.** PROCESIO does a blind textual replace of every
|
|
423
|
+
`<%N%>` in a Node's code, including `// comment` lines. If the injected value is a JSON
|
|
424
|
+
list/object, the `:` / quotes inside break the surrounding line and the Node dies with
|
|
425
|
+
"Unexpected token ':'" (returns null). **Never put `<%N%>` in a Node comment.** (The Node body is
|
|
426
|
+
syntactically valid on its own `node --check`, so this only reproduces live — check by
|
|
427
|
+
substituting a REAL value, not a stub.)
|
|
428
|
+
|
|
429
|
+
- **Execute Query always returns a LIST of row-objects**, and **bare-injecting a list whose column
|
|
430
|
+
value is a JSON STRING corrupts the JS** (PROCESIO unescapes the inner `\"` -> invalid literal).
|
|
431
|
+
Fix: return **scalar columns** (`JSON_VALUE(cd,'$.a.b') AS x`) so the injected list has no nested
|
|
432
|
+
quotes, OR strip the JSON into a scalar string bound in backticks. A list of simple scalar
|
|
433
|
+
columns bare-injects cleanly.
|
|
434
|
+
|
|
435
|
+
- **The "generic" datatype `8daff4fc-206c-4151-9bad-1cfdec59bfbd` is NOT free-form — it is a fixed
|
|
436
|
+
10-column model** (the LLMFastData schema). Any extra column a proc SELECTs (e.g. an appended
|
|
437
|
+
`currentSessionId`, or your own scalar columns) is **silently DROPPED** when coerced into a var of
|
|
438
|
+
that type. For a truly column-preserving passthrough use the **object datatype `…121221`** (as a
|
|
439
|
+
list). This dropping can happen at MULTIPLE hops — fix the var type at every hop (subprocess output
|
|
440
|
+
var AND the parent var it maps into).
|
|
441
|
+
|
|
442
|
+
- **Whole-body RAW `<%0%>` for a dynamic JSON body works only with an OBJECT var + Node `return
|
|
443
|
+
body` (object)** and the Node's **Single Result dataTypeId set to object `…121221`**. A Text var
|
|
444
|
+
holding `JSON.stringify(body)` sends a double-encoded string (WhatsApp: "messaging_product is
|
|
445
|
+
required"); an inline template with an unquoted `"k":<%1%>` fails PROCESIO's pre-substitution
|
|
446
|
+
RAW-JSON validator ("invalid Json format for RAW type value"). Proven working precedent:
|
|
447
|
+
`Chat Flow/Call LLM Fast` (`<%0%>` <- object-return Node).
|
|
448
|
+
|
|
449
|
+
- **A proc that ends with `SELECT …` (e.g. `SELECT @@ROWCOUNT`) adds a result set.** Calling it via
|
|
450
|
+
`EXEC` inside an Execute Query that already returns one set -> "Expected maximum one table but
|
|
451
|
+
received 2 tables!". For a fire-and-forget pointer/side-effect write, inline the `UPDATE` in the
|
|
452
|
+
SQL (no `SELECT`) instead of `EXEC`-ing the proc.
|
|
453
|
+
|
|
454
|
+
- **Required subprocess inputs abort the caller.** A `Call Subprocess` whose target has an
|
|
455
|
+
`isRequired=true` input var will abort the WHOLE parent with "Missing required input for
|
|
456
|
+
variables: <type>" if that input resolves to null/missing at runtime — silently killing everything
|
|
457
|
+
downstream. (This is how the DB-wave `Escape Quotes - search_id` node broke all new-contact
|
|
458
|
+
persistence: a fresh extraction has no search_id.) Guard the value, or don't route an
|
|
459
|
+
optional/empty value through a required-input subprocess.
|
|
460
|
+
|
|
461
|
+
- **A proc-parameter value cannot be a T-SQL expression.** `EXEC sp_X @p = CASE WHEN … END` is a
|
|
462
|
+
syntax error ("Incorrect syntax near the keyword 'CASE'"). Compute into a local first:
|
|
463
|
+
`DECLARE @v bit = CASE …; EXEC sp_X @p = @v`.
|
|
464
|
+
|
|
465
|
+
Networky flow ids added this wave: `Resolve And Patch` = `cd337769-d9e0-4f13-9787-b4a219aeb0ec`
|
|
466
|
+
(sp_FindContact + patch ResponseLLM target + pending write); `Get Pending` =
|
|
467
|
+
`98e3fd5f-a6b9-4da0-87fc-e2d88180818c`. Report:
|
|
468
|
+
`work/networky/migrations/reports/dbwire-e2e.md`.
|
|
469
|
+
|
|
470
|
+
---
|
|
471
|
+
|
|
472
|
+
## AI Decisional action + Map Data + subprocess-extraction recipes (Networky AI-router refactor, 2026-07)
|
|
473
|
+
|
|
474
|
+
Building the single-router refactor of `Start` (87→43 nodes) surfaced concrete recipes for three
|
|
475
|
+
constructs. All verified via `flowpatch validate` (POST /api/Projects/validate → 200) on a live clone.
|
|
476
|
+
|
|
477
|
+
### AI Decisional node (template `772aac51-73f5-471d-bf9f-f5099cb30001`, diamond, in1/out-1)
|
|
478
|
+
- **Credential is NOT a validation blocker.** A probe with the platform-export credential gid
|
|
479
|
+
`adc0e765-…` (template `27272727-0001-0000-0000-aaaaaaaaaaaa`, a system/global instance) validated
|
|
480
|
+
fine even though no AI credential exists in the target workspace. Validation checks node/port SHAPE,
|
|
481
|
+
not credential ownership. For LIVE RUNS you still need a workspace-owned, tested AI credential of that
|
|
482
|
+
template (create + `credential-test`, then rebind param `…30111` + the customData `credentials`
|
|
483
|
+
setting). The `/api/Credentials/types` + `/list/{typeId}` endpoints 403 with the userpass tool token.
|
|
484
|
+
- **Params** (tabPropertyId suffixes off `772aac51-73f5-471d-bf9f-f5099cb3____`): `0111` credential,
|
|
485
|
+
`0112` Model (text), `0113` Endpoint (select 1=Chat Completions/2=Responses), `0114` User Prompt
|
|
486
|
+
(code-editor, `<%N%>`), `0115` Timeout, `0123` LLM Response (datatype dir3 OUTPUT, diagnostic),
|
|
487
|
+
`0116`-`0122` temp/topP/maxtok/presence/freq/seed/store, `0124` Cases (`ai-decisional-case` list),
|
|
488
|
+
`0125` Default (`decisional-default`).
|
|
489
|
+
- **Cases** param value = `[{id, actionid:<targetActionId>, condition:"<free text>"}]`; customData mirror
|
|
490
|
+
= `[{id,name,target,condition,internalId}]`. **First true case (declared order) wins.**
|
|
491
|
+
- **Ports:** one Type-0 port per case target + one Type-0 default port (`data:{"isDefault":"default"}`)
|
|
492
|
+
+ one **Type-1 error port** (`data:{"isDefault":"error"}`). Node carries `variableErrorId` = an
|
|
493
|
+
**IsError var whose datatype MUST be `10c6ac59-3929-49e6-99dc-121212121220`** (validate error 395
|
|
494
|
+
"invalid data type for error variable" if you use plain string `…214`).
|
|
495
|
+
- **User Prompt type gotcha:** the User Prompt (`0114`) is a STRING slot — injecting an OBJECT-typed var
|
|
496
|
+
via `<%0%>` fails validate 142 "data type mismatch". Also a `text`-typed var (`…220`) mismatches; it
|
|
497
|
+
wants a **string** var (`…214`). To feed a structured object to the prompt, add a `Node` before it that
|
|
498
|
+
`return JSON.stringify(<%0%>)` into a **string** Single-Result var, and inject THAT.
|
|
499
|
+
|
|
500
|
+
### Map Data node (template `f183b48e-25b0-4a28-b6ec-310344feaa18`, `icon-variables`)
|
|
501
|
+
- ONE side-pannel setting `a5f92824-…` → child `map-process-data` setting `d7ffa148-…`.
|
|
502
|
+
- **customData** map value = `[{id, destination:<targetVarId[.attr]>, source:<srcVarId[.attr]>}]`
|
|
503
|
+
(destination = LEFT/assigned var, source = RIGHT/value).
|
|
504
|
+
- **Runtime param** `d7ffa148-…` value = `[{id, source:{value:"<%N%>", variable:[{variableId,attribute}]},
|
|
505
|
+
destination:{variableId,attribute}}]`. destination assigned FROM source. Used here as `Map Route A/B`
|
|
506
|
+
to normalize two per-branch router DTOs into one shared `Route` var + a `routeSessionId` guid.
|
|
507
|
+
|
|
508
|
+
### Extract a duplicated tail into a subprocess (the higher-value merge)
|
|
509
|
+
- **POST /api/Projects 403s** with the tool token — you cannot create a process from scratch. Instead:
|
|
510
|
+
**`duplicate-process` any small flow → get a fresh flow id → overwrite its actions/variables with your
|
|
511
|
+
DTO (keep the duplicate's id, propagate it to every action.flowId + port.flowId) → validate → PUT.**
|
|
512
|
+
- A **Call Subprocess input/output map** entry (in `parameters[].value`) is
|
|
513
|
+
`{id, source:{value:"<%N%>", variable:[{variableId, attribute}]}, destination:{id, variableId, attribute}}`.
|
|
514
|
+
For an INPUT map: source=PARENT var, destination=CHILD input var. For an OUTPUT map: source=CHILD output
|
|
515
|
+
var, destination=PARENT var. When re-homing onto a new subprocess you must remap BOTH
|
|
516
|
+
`source.variable[].variableId` AND `destination.variableId` when they are parent vars (missing the
|
|
517
|
+
destination side leaves stale refs). customData mirror uses `{subprocess:<child id>, process:<parent
|
|
518
|
+
id[.attr]>}`.
|
|
519
|
+
- **A called subprocess needs `active:true` AND `isValid:true`** or the parent validate returns 504
|
|
520
|
+
"Called suprocess is not valid". After building, `flowpatch validate` the subprocess, set `isValid:true`,
|
|
521
|
+
and PUT it BEFORE validating the parent that calls it.
|
|
522
|
+
|
|
523
|
+
### Networky ids added this wave (AI-router refactor, on a CLONE — not live)
|
|
524
|
+
- Refactored clone `Start [AI-Decisional REFACTOR - not live]` = `5dabbaaa-5de0-44cc-ab89-9a307fb90c5e`
|
|
525
|
+
(43 nodes, active:false, isValid). Report: `work/networky/migrations/reports/ai-decisional-refactor.md`.
|
|
526
|
+
- New subprocess `Chat Flow/Handle Complex Turn` = `68a0c9d1-f55b-44bc-ba36-748397093f25` (single copy of
|
|
527
|
+
the complex/enrichment/persist tail; input `session_id` guid required + conversation/User/userMsg/route).
|
|
528
|
+
- The live `fastLLM` router DTO (`be898da6-5e1a-42a0-a6c4-6ad653e8f7e9`) has exactly 7 fields:
|
|
529
|
+
response_text(17522760) send_message(723db89f) need_LLM_complex(0b778bf1) language(77c01d02)
|
|
530
|
+
new_session(4b0fc63b) target_session_id(926d5723) intent(7f56f2b4). `need_contact_search` is NOT a typed
|
|
531
|
+
field — it lives only in the RAW router JSON text var `fastLLMRaw`, read by the `Check Search` Node.
|
|
532
|
+
- The WTB webhook `db92281a-17b5-451f-b9f4-2a7f6a70f1fc` stays bound to LIVE `Start`
|
|
533
|
+
`c6754fc4-…`; a duplicated process carries the same webhookId reference but is inert while `active:false`.
|
|
534
|
+
|
|
535
|
+
|
|
536
|
+
## Creating nodes/actions in a flow via API (WORKS - userpass; verified 2026-07-05)
|
|
537
|
+
|
|
538
|
+
Adding a NEW node to a flow via `PUT /api/Projects` works with the default userpass `account` profile.
|
|
539
|
+
No designer UI needed. The one trap: do NOT copy an existing node to make a new one - a copied node
|
|
540
|
+
carries the source flow's stale variable bindings in `customData.configuration`, and the validator then
|
|
541
|
+
throws a diagnostic-free `HTTP 500 "Object reference not set to an instance of an object"` (changed in v3.0.0, 2026-10: an unhandled 500 no longer carries the exception text; the body is now the generic `[{"statusCode":100,"value":"An unexpected error occurred.","target":null}]`, so treat that body on a flow PUT as the same symptom). Instead:
|
|
542
|
+
|
|
543
|
+
1. Fetch the CLEAN action template: `GET /api/Actions?getFullAction=true`, find by `actionId`/`name`.
|
|
544
|
+
`copy.deepcopy(template.configuration)` and fill only your setting values. A clean config makes the
|
|
545
|
+
validator return REAL errors (141/142) instead of the 500.
|
|
546
|
+
2. A JS "Node" (templateId e0fc20c3): settings are Code (1e6a5523) = JS + input `<%N%>` bound in the
|
|
547
|
+
Code param's `variable` list; **Single Result** (51b9fcdc) = the JS `return` output (NOT Error
|
|
548
|
+
9e0110c9); List Result (60237e88); Error (9e0110c9) = error port; Timeout (d3e52aab).
|
|
549
|
+
3. New variables use key **`dataType`** (a type id) + `type` (10 input / 20 process / 30 output / 40 sys).
|
|
550
|
+
Missing type -> `statusCode 141 "type cannot be empty"`. Param/var type must MATCH the setting's
|
|
551
|
+
expected `dataTypeId` -> else `statusCode 142 data type mismatch`. Primitive ids: `...1211` number,
|
|
552
|
+
`...1214` string, `...1221` any/object; file `10c6ac59-...-121212121219` = FileDataModel
|
|
553
|
+
`{name,mimeType,path,size,id,hash}` (blob reference, NOT inline content).
|
|
554
|
+
4. Files from text: a Node cannot return a FileModel (no inline content). Use **`Base64 To File`**
|
|
555
|
+
(actionId 6fad5599; settings Base64 String, File Name -> File output) to turn a base64 string into a
|
|
556
|
+
stored FileModel; then Call API `/media` upload (FORM_DATA `file`=FILE type, `type`=mime).
|
|
557
|
+
5. Validate via `POST /api/Projects/validate` (empty body = valid) before PUT.
|
|
558
|
+
|
|
559
|
+
Best path: `tools/procesio/dto/process/builder.py` already builds correct DTOs data-driven from the live
|
|
560
|
+
catalog (`_action_node` = clean template config + values; `_edit` rebuilds a whole flow and PUTs). Prefer
|
|
561
|
+
it for full-flow builds; replicate `_action_node`'s recipe for a surgical single-node insert into a
|
|
562
|
+
fetched (lowercase-keyed) flow. Worked example: added Build VCF (Node) + Base64 To File to Chat Flow/Send
|
|
563
|
+
Export to produce a `.vcf` bulk export (scratchpad build_vcf_flow3.py pattern).
|
|
564
|
+
|
|
565
|
+
|
|
566
|
+
## Field learnings 2026-07-05 (designer review + real-corpus E2E) — AUTHORITATIVE
|
|
567
|
+
|
|
568
|
+
1. **Decisional icon**: when creating a Decisional via API set `customData.icon = "call_split"` (the
|
|
569
|
+
designer standard). `icon-decisional` or anything else renders NO icon in the run view. Same rule
|
|
570
|
+
class: give decisional CASES meaningful `name`s — the designer shows them as chips on the canvas.
|
|
571
|
+
2. **Scripting (Node) actions FAIL SILENTLY**: a JS code error does NOT raise / does NOT take the
|
|
572
|
+
type-1 error port. The action reports SUCCESS and writes the error text to its **Error output**
|
|
573
|
+
setting (9e0110c9). ALWAYS: (a) bind Error output to a string var on every Node; (b) on hot paths,
|
|
574
|
+
follow the Node with a Decisional `errVar IS_NOT_EMPTY -> error join`; (c) compose the user-facing
|
|
575
|
+
error message from the error vars in one downstream Node (values from the FAILED action are unset —
|
|
576
|
+
never map them into the notice directly). Proven: 6 silently-dying turns became 6 successes.
|
|
577
|
+
3. **Huge values (base64 media) are NOT an engine limit** (corrected 2026-09-21). A controlled probe through
|
|
578
|
+
`/run` carried a 4 MB string intact through a Node `<%N%>` injection, a Decisional `IS_NOT_EMPTY`, the native
|
|
579
|
+
**Length** action (template 057d754a: Input String, Result), Map Data, subprocess maps and SQL parameters, on a
|
|
580
|
+
plain variable and on a data-model attribute alike. The earlier note that 100 KB+ values "materialize as EMPTY"
|
|
581
|
+
in a Node or Decisional was an artefact of the middleware that fed the flow (it capped its own payload), not of
|
|
582
|
+
PROCESIO. Length is still the cheapest way to test a big value's presence; it is not a workaround.
|
|
583
|
+
4. **For Each via API** (template dbef0804-66a9-4f8f-872c-ece1b89b8fdb, shape `area`): params =
|
|
584
|
+
For Each Item (57b5b1eb…, the per-iteration var) + In List (2d5f230f…) + timeout + 2 ignore
|
|
585
|
+
literals. The FE node has TWO type-0 ports: first -> loop-body entry child, second -> the after-loop
|
|
586
|
+
node. Children carry `parentId` = FE id; the LAST child ports BACK to the FE (loop-back edge).
|
|
587
|
+
5. **Workspace header is mandatory on run/launch**: `ProcesioClient(workspace_id=…)`. Without it,
|
|
588
|
+
`/api/Webhooks/launch` and `run-process` bind LARGE attribute values as EMPTY (looks like an engine
|
|
589
|
+
bug, is actually your missing header), and admin flows 400/502.
|
|
590
|
+
6. **WhatsApp bulk contact export**: document sends get the MIME's extension APPENDED by WhatsApp
|
|
591
|
+
(filename `Contacts.vcf` + text/plain ⇒ phone receives `Contacts.vcf.txt`, unimportable). No allowed
|
|
592
|
+
/media MIME maps to .vcf. Correct approach: native `type:"contacts"` messages (array, chunk ~15 per
|
|
593
|
+
message, For Each over chunks) — renders as a tappable contact stack ("X and N other contacts").
|
|
594
|
+
|
|
595
|
+
|
|
596
|
+
## Layout engine upgrade 2026-07-05 (brief: "fix the tool so it layouts right")
|
|
597
|
+
|
|
598
|
+
Four engine changes in `tools/procesio/layout/engine.py` (all covered by the existing test suite):
|
|
599
|
+
1. **Error-region detection stops AT error targets**: main-flow reach may point INTO an error-port
|
|
600
|
+
target (e.g. a script-gate's normal case edge into the shared error Join) but never THROUGH it.
|
|
601
|
+
Before, one normal edge into the sink pulled the whole notify subtree into the main graph.
|
|
602
|
+
2. **ALAP layer pull with branch-head anchoring**: single-successor chains get pulled RIGHT adjacent
|
|
603
|
+
to their join (kills 8-layer join edges), but a branch HEAD (predecessor fans out) keeps its ASAP
|
|
604
|
+
layer so it stays next to its decisional.
|
|
605
|
+
3. **Error components anchor independently, laid VERTICALLY**: each weakly-connected component of the
|
|
606
|
+
error region becomes a vertical rail below the canvas, anchored at the median x of ITS OWN feeders.
|
|
607
|
+
Vertical rails cannot cross the horizontal main flow.
|
|
608
|
+
4. **MINIMIZE_CROSSINGS defaults ON** (strictly better in every measurement).
|
|
609
|
+
|
|
610
|
+
FLOW-side pattern that finishes the job: with feeders spread across a wide canvas, a SINGLE shared
|
|
611
|
+
error Join forces ~feeder-span-length edges (geometry, not layout). Split into ONE ERROR RAIL PER
|
|
612
|
+
CANVAS REGION (Networky v2: rails A/left/right - Join+Compose+notice+Stop each, cloned). Result on
|
|
613
|
+
the 78-node v2: crossings 10 -> 0 (proper-intersection; report's endpoint-touch counter: 2),
|
|
614
|
+
max edge 3729 -> ~1500, all four Networky flows re-laid clean.
|
|
615
|
+
LEGACY engine remains the default (ELK is opt-in backup via LAYOUT_ENGINE=elk).
|
|
616
|
+
|
|
617
|
+
|
|
618
|
+
### Layout round 2 (same day, after the designer re-review)
|
|
619
|
+
5. **At most ONE folded dead-end chain per branch node** (`_deadend_chains` cap): several chains
|
|
620
|
+
folding onto the same column stacked into overlapping piles (the AI Router 5-way fan). The
|
|
621
|
+
shortest chain folds; the rest lay out normally. Result incl. label-aware collision check:
|
|
622
|
+
v2 = 0 crossings, 0 label collisions; ALL FOUR flows 0/0 by layout-report.
|
|
623
|
+
6. **Designer code sync for authored Nodes**: when creating a Node via API, the customData Code
|
|
624
|
+
setting must hold the GUID-reference form (variableId[.attributeId]), NOT the runtime `<%N%>`
|
|
625
|
+
form — the designer renders `<%N%>` literally and the variable picker breaks. Convert with
|
|
626
|
+
the param's variable map (flowpatch `_config_value_from_param` pattern). Synced on 9 authored
|
|
627
|
+
Nodes across v2/HCT/SendExport/PEC.
|
|
628
|
+
|
|
629
|
+
|
|
630
|
+
### TWO validation layers — runtime vs designer (2026-07-06, corrected)
|
|
631
|
+
**A 2026-07-05 note here WRONGLY called the designer's Process Errors "stale phantoms." They were
|
|
632
|
+
REAL and blocked designer SAVE. Corrected below — trust the designer's Process Errors.**
|
|
633
|
+
|
|
634
|
+
- There are TWO validation layers and they disagree:
|
|
635
|
+
- **Runtime layer** — `POST /api/Projects/validate` (the only server validate endpoint; by-id
|
|
636
|
+
variants 403). It checks `parameters[]` (the runtime maps). Returns an EMPTY body when valid.
|
|
637
|
+
It does NOT look at the designer layer, so a flow can pass /validate yet be UNSAVABLE.
|
|
638
|
+
- **Designer layer** — a CLIENT-SIDE check in the Angular designer that populates the "Process
|
|
639
|
+
Errors" panel and BLOCKS SAVE. It reads `customData` (the designer maps + code chips). There is
|
|
640
|
+
NO server endpoint for it — you must replicate it.
|
|
641
|
+
- **Replicate the designer layer with `procesio flow-lint --id <flow> --workspace-id <ws>`** (rewritten
|
|
642
|
+
2026-07-06 to check the DESIGNER layer, not the runtime one): Node code binding an error-scope
|
|
643
|
+
(`isError=true`) or undeclared variable; and every REQUIRED subprocess input having a `customData`
|
|
644
|
+
process-inputs row (`subprocess`==input id) whose source resolves (GUID source must be a declared
|
|
645
|
+
var; a non-GUID source is a literal and is fine). Call inputs pid 62cdd318…, Trigger 9823b4d9-7a0c….
|
|
646
|
+
- **Root cause we hit twice:** cloning a Call/Trigger-Subprocess node copies its `customData`
|
|
647
|
+
process-inputs verbatim, so the clone keeps the SOURCE node's subprocess-input ids. The real target
|
|
648
|
+
requires DIFFERENT ids → those read as "mapping missing," and the panel shows the stale ids as raw
|
|
649
|
+
GUIDs (they don't resolve in the new target). Fix: regenerate `customData` process-inputs from the
|
|
650
|
+
(correct) runtime map — row `{id, subprocess: <dest varId>, process: <srcVarId>[.<attrId>]}`;
|
|
651
|
+
literals go in `process` verbatim.
|
|
652
|
+
- **Runtime map ≠ designer map.** A node's runtime `parameters` map can be correct while its
|
|
653
|
+
`customData` designer map is stale (Networky v2: Resolve And Patch). The designer validates the
|
|
654
|
+
DESIGNER map. Always sync both when authoring/cloning subprocess nodes and Node code.
|
|
655
|
+
- Error-scope variables (`isError=true`, usually FileDataModel) are an action's error-PORT output;
|
|
656
|
+
they live in the designer's "Error" tab, never appear in the Process tab, and are never
|
|
657
|
+
free-initialized. NEVER bind one as a Node code INPUT — the designer flags it (tooltip shows type
|
|
658
|
+
"Error"). Networky v2's Compose Error wrongly swept 9 of them in via a `name.startswith("err_")`
|
|
659
|
+
filter; rebuilt to bind only the real String gate-error vars.
|
|
660
|
+
- Overhaul-era subprocesses do use VANITY input ids (11111111-0000-4000-…, a1b2c3d4-0000-4000-…) that
|
|
661
|
+
are REAL — but that does not make a mapping to them automatically correct; check that the id belongs
|
|
662
|
+
to THIS node's target, not a sibling's.
|
|
663
|
+
- `flowpatch.py validate` USED to print `validated:True` unconditionally without reading the response
|
|
664
|
+
(fixed 2026-07-06 to inspect the body + fail loudly). Any pre-fix "validate: True" was meaningless.
|
|
665
|
+
|
|
666
|
+
### Designer-layer validation: the concrete rules (2026-07-06, hard-won)
|
|
667
|
+
`procesio flow-lint --id <flow>` now checks ALL of these (the designer's client-side "Process Errors"
|
|
668
|
+
that block SAVE; POST /Projects/validate does NOT catch them). Root causes found by comparing a
|
|
669
|
+
FLAGGED node against a HEALTHY node of the same template against the CLEAN /api/Actions template — that
|
|
670
|
+
comparison is the reliable method; reverse-engineering from a single node's data is not.
|
|
671
|
+
|
|
672
|
+
1. **Stale subprocess side-pannel id (THE big one).** A Call/Trigger Subprocess node's
|
|
673
|
+
"Subprocess Configuration" side-pannel setting has an `id` that MUST equal the CURRENT template's
|
|
674
|
+
side-pannel id: Call = `5456caf0-be8e-4a04-86cb-dbae203af978`, Trigger =
|
|
675
|
+
`8540605e-2f4d-1746-9059-8bb7b944e0d3`. PROCESIO bumped this id across template versions; nodes
|
|
676
|
+
built/cloned against an older template keep the OLD id (seen: `1da555da…`, `15af8b81…`). The
|
|
677
|
+
designer looks the mapping up BY this id — wrong id ⇒ it finds nothing ⇒ reports EVERY required
|
|
678
|
+
input as "Mapping of required subprocess variable (X) is missing." The mapping CONTENT is fine;
|
|
679
|
+
only the wrapper id is stale. Fix: set the side-pannel `id` to the current template's; leave the
|
|
680
|
+
nested process-inputs/outputs untouched. This is safe and mechanical.
|
|
681
|
+
2. **Required subprocess input unmapped / dead source.** Every target input (type 10, isRequired)
|
|
682
|
+
needs a process-inputs row `{id, subprocess:<targetInputId>, process:<srcVarId>[.<attrId>]|literal}`;
|
|
683
|
+
a GUID source must resolve to a declared var (a non-GUID is a literal, fine).
|
|
684
|
+
3. **Subprocess output must map a type-30 var.** A subprocess only EXPOSES `type==30` variables as
|
|
685
|
+
outputs. Mapping a `type==20` internal var (e.g. an Execute Query `dbout`) as a process-output ⇒
|
|
686
|
+
designer "Check data mapping." To read a value out of a subprocess, that var must be type 30 there.
|
|
687
|
+
4. **Execute Query requires a non-null Output.** The Output subsection (label "Output", pid
|
|
688
|
+
`8aa02e91-1a1e-a44a-b09b-6965d67da04d`) must be set to a variable, both as a runtime param and in
|
|
689
|
+
customData. Null ⇒ "make sure the action is defined/configured properly."
|
|
690
|
+
5. **Node code must not bind an isError variable** (an action's error-port output; type shown as
|
|
691
|
+
"Error", never free-initialized) nor an undeclared var.
|
|
692
|
+
|
|
693
|
+
### Designer-layer rule #6 — Execute Query Output must be a list<Object> (2026-07-06)
|
|
694
|
+
Another client-side "data type mismatch" the server /validate does NOT catch. An `Execute Query`
|
|
695
|
+
returns a SQL result SET, so its **Output** variable must be a `list<Object>`: `isList = true` AND the
|
|
696
|
+
element type an Object - the generic `0317bfee-b2f5-4bde-bfe8-121212121221` (any/Object) OR any custom
|
|
697
|
+
DataModel (whose GUID does not share the `0317bfee-b2f5-4bde-bfe8-1212…` scalar prefix). A scalar
|
|
698
|
+
(e.g. a `number` output `…1211`, isList=false) or a `list<primitive>` (e.g. `list<text>` `…1220`)
|
|
699
|
+
trips "Error: data type mismatch" and blocks SAVE. Typed-DM lists (`list<UserDM>`, `list<MessageDM>`)
|
|
700
|
+
are fine - a DataModel IS an Object. `procesio flow-lint` now checks this (EXECQUERY_OUTPUT_TYPE).
|
|
701
|
+
Fix: set the Output var's dataType to the generic Object (or a DM) and isList=true; the var id on the
|
|
702
|
+
Output setting is unchanged. Found live on `Persist search_id` (SalesOMMO, scalar number) and
|
|
703
|
+
`sp_MessageAdd` (Add Message, list<text>) - both corrected to list<Object>.
|
|
704
|
+
|
|
705
|
+
## Shapes (canvas-engine PRC-4391, 2026-08)
|
|
706
|
+
|
|
707
|
+
Decorative canvas Shapes (rectangle / ellipse / diamond) are NOT flow nodes: no ports, no
|
|
708
|
+
config, no execution. They persist as `ICanvasShape[]` under the flow DTO's opaque
|
|
709
|
+
**`canvasData.shapes`** blob (live API camelCase `canvasData`; PUT DTO PascalCase
|
|
710
|
+
`CanvasData`) — NOT a top-level `Flow.shapes` field. Z-order sits below the connectors.
|
|
711
|
+
Designer save/load of shapes is platform Phase 2. **Tool rule: never drop `canvasData` on
|
|
712
|
+
a round-trip.** `process-edit` now carries the live `canvasData` into the rebuilt DTO
|
|
713
|
+
(build() resets it to None); the layout/relayout engine already leaves `canvasData`
|
|
714
|
+
byte-identical. A hand-authored PUT must preserve it or every shape is wiped.
|
|
715
|
+
|
|
716
|
+
## DataStore form event (2026-08)
|
|
717
|
+
|
|
718
|
+
`EventAction.RUN_DATA_STORE_OPERATION`; config `EventRunDataStoreOperationConfig
|
|
719
|
+
{dataStoreId, operation, inputMap, outputMap, filters?, areFiltersConfigured?}`.
|
|
720
|
+
`operation` = DataStoreOperation READ/ADD/UPDATE/DELETE; filters apply to every op except
|
|
721
|
+
ADD (`dataStoreOperationSupportsFilters`). Map items are `{id, left, right}`
|
|
722
|
+
(DataStoreMapItem). Wired via `form-set-element-event --action RUN_DATA_STORE_OPERATION`
|
|
723
|
+
(surgical) or the builder `do: datastore`. Operation wire encoding (string vs numeric) +
|
|
724
|
+
map orientation confirmed live post-launch.
|
|
725
|
+
|
|
726
|
+
## A platform-seeded data model cannot be deleted
|
|
727
|
+
|
|
728
|
+
`DELETE /api/DataTypes/{id}` on a model the platform seeded into the workspace returns HTTP 400 with
|
|
729
|
+
|
|
730
|
+
{"statusCode": 452, "value": "Unauthorized data type change!", "target": "data_type"}
|
|
731
|
+
|
|
732
|
+
Seeded models are not distinguishable by guid prefix the way the primitive types are, and one of them
|
|
733
|
+
can even carry a real user as `createdBy` (the account that first opened the workspace), so neither
|
|
734
|
+
the id nor the author tells you. Treat 452 as the answer: **an unreferenced model that refuses to
|
|
735
|
+
delete is the platform's, not a leftover of yours.** A tidy-the-workspace pass should report those
|
|
736
|
+
rather than keep retrying them.
|
|
737
|
+
|
|
738
|
+
## ProcessInfo is a declared variable, not an ambient object
|
|
739
|
+
|
|
740
|
+
The platform's per-run facts are reached through a flow variable, so a flow that never
|
|
741
|
+
references them does not have it:
|
|
742
|
+
|
|
743
|
+
{"Id": "<per-flow guid>", "ContextId": null,
|
|
744
|
+
"DataType": "10c6ac59-3929-49e6-99dc-121212121221", // SystemDataModel
|
|
745
|
+
"Type": 40, "Name": "ProcessInfo",
|
|
746
|
+
"DefaultValue": null, "IsList": false, "IsError": false, "IsRequired": false}
|
|
747
|
+
|
|
748
|
+
Its fields are attributes of `SystemDataModel`:
|
|
749
|
+
|
|
750
|
+
| field | attribute id |
|
|
751
|
+
|---|---|
|
|
752
|
+
| `workspaceId` | `75044bb4-7c70-40f2-8756-21c03de655c8` |
|
|
753
|
+
| `instanceId` | `d3c32b47-df62-4376-8a82-f8f9aff7d6d0` |
|
|
754
|
+
| `templateId` | `3a36d9ea-0fd8-4d4a-a89b-8f297c5d0098` |
|
|
755
|
+
| `name` | `0a5d51bc-2550-4291-a56c-cb027f8db966` |
|
|
756
|
+
| `startedOn` | `75044bb4-7c70-40f2-8756-21c03de655c9` |
|
|
757
|
+
|
|
758
|
+
Bind a field like any model-typed variable: a `<%N%>` placeholder whose `variable[]` entry is
|
|
759
|
+
`{variableId: <the flow's ProcessInfo id>, attribute: <the attribute id>}`.
|
|
760
|
+
|
|
761
|
+
**The designer adds it the first time something references it, which makes it easy to lose.**
|
|
762
|
+
A flow rebuilt from a compact config keeps only the variables the config lists, so a rebuild
|
|
763
|
+
drops ProcessInfo from every flow that had it, silently, because nothing references it
|
|
764
|
+
afterwards. Declare it with `direction: "processinfo"`.
|
|
765
|
+
|
|
766
|
+
**Prefer `ProcessInfo.workspaceId` over any stored copy of the workspace id.** It is always
|
|
767
|
+
right, needs no configuration, and survives an import into another workspace - where a literal
|
|
768
|
+
in an action parameter does not, since an import rewrites a resource's own `workspaceId`
|
|
769
|
+
metadata but never a value inside a parameter.
|
|
770
|
+
|
|
771
|
+
## What a Transport export/import actually carries (verified cross-tenant, 2026-09)
|
|
772
|
+
|
|
773
|
+
Measured by exporting a whole working product out of one workspace and importing it into a
|
|
774
|
+
workspace under a **different master**, then diffing both sides resource by resource. The summary
|
|
775
|
+
a packager needs: **the graph travels, the environment does not.** Everything a flow points at
|
|
776
|
+
that lives outside the flow is either absent from the pack or present only as an id the new
|
|
777
|
+
workspace cannot resolve.
|
|
778
|
+
|
|
779
|
+
### Travels, intact
|
|
780
|
+
|
|
781
|
+
| Carried | Detail |
|
|
782
|
+
| --- | --- |
|
|
783
|
+
| Flows, forms, data stores, data models | every one, **with its original id** |
|
|
784
|
+
| Cross-references between them | consequently survive: a form's RUN_PROCESS map binds a process by id, so it still resolves |
|
|
785
|
+
| A form's encrypted `Data.code` | global CSS + JS decrypt byte-identically in the new workspace, so the key is not per-workspace |
|
|
786
|
+
| A form's `IsPrivate` | privacy is part of the form, not of the environment |
|
|
787
|
+
| Action names and canvas coordinates | the readability work is in `customData`, which is part of the flow |
|
|
788
|
+
| `Active` and `IsValid` | **carried verbatim, not recomputed** — see the trap below |
|
|
789
|
+
|
|
790
|
+
A platform-seeded data model is skipped rather than duplicated: those ids are identical in every
|
|
791
|
+
workspace (the `…12121212121x` family plus a few named ones), so the importer finds them already
|
|
792
|
+
present. Only genuinely custom models are created.
|
|
793
|
+
|
|
794
|
+
### Does NOT travel
|
|
795
|
+
|
|
796
|
+
| Absent | Consequence in the new workspace |
|
|
797
|
+
| --- | --- |
|
|
798
|
+
| **Data store ROWS** | every imported store arrives with the right columns and zero rows |
|
|
799
|
+
| **Credentials**, when the export names none | excluded, and the ids stay baked into the nodes (below). Name them and the records DO travel, secrets withheld - see "Ship the credentials in the pack" |
|
|
800
|
+
| **Schedules** | anything time-driven simply never fires, with no error anywhere |
|
|
801
|
+
| **API keys** | a key is per workspace; a setting that holds one arrives empty |
|
|
802
|
+
| **CustomUrl / tinyUrl**, at workspace AND entity level | **the forms are not reachable at any address** |
|
|
803
|
+
|
|
804
|
+
### The trap: a credential is a node parameter, so an export WITHOUT them leaves dangling references
|
|
805
|
+
|
|
806
|
+
A credential slot is `CustomData.configuration[].settings[].type == "credentials"`, and the chosen
|
|
807
|
+
credential lands in the node's `Parameters[].Value` as the credential INSTANCE gid. That gid is
|
|
808
|
+
part of the flow, so it travels — pointing at a credential that does not exist in the new
|
|
809
|
+
workspace. Nothing rewrites it, and nothing warns: the flows arrive with `IsValid: true` because
|
|
810
|
+
validity is client-set and simply carried over, so the workspace looks healthy while every
|
|
811
|
+
credential-bearing node is broken.
|
|
812
|
+
|
|
813
|
+
The failure is at least precise, and it happens while building the input model, i.e. before the
|
|
814
|
+
node does anything:
|
|
815
|
+
|
|
816
|
+
```
|
|
817
|
+
Error while building input model: Error while getting credential <gid> for workspace <new-ws-id>.
|
|
818
|
+
```
|
|
819
|
+
|
|
820
|
+
The run ends at status 40 and names the action. Two consequences worth designing around:
|
|
821
|
+
|
|
822
|
+
- **A flow fails whole, not partially.** Nodes before the credential node DO commit their work
|
|
823
|
+
(a seeding branch ahead of an API call still seeds), so a failed bootstrap can still leave the
|
|
824
|
+
stores correctly populated. Check state before concluding that nothing ran.
|
|
825
|
+
- **A form whose FORM_LOAD launches such a flow cannot populate.** If that form is the product's
|
|
826
|
+
own setup screen, the new user cannot reach the screen they need in order to fix the problem.
|
|
827
|
+
Keep the nodes that need a credential OFF the load path of the screen that configures them, or
|
|
828
|
+
let them tolerate a missing credential, or the product is unreachable until someone edits it in
|
|
829
|
+
the designer.
|
|
830
|
+
|
|
831
|
+
Re-pointing is scriptable rather than manual: the process config accepts a `{credential: <gid>}`
|
|
832
|
+
binding for that parameter, so a whole workspace can be remapped from one credential to another in
|
|
833
|
+
one pass per flow.
|
|
834
|
+
|
|
835
|
+
### Rows not travelling is also a safety property
|
|
836
|
+
|
|
837
|
+
It is the reason a pack cannot leak the exporter's configuration or their customers' records: a
|
|
838
|
+
key/value settings store carrying an API key, a logo, an owner's address, and an operational table
|
|
839
|
+
of real bookings all stay behind. So a "publishable" pack is not achieved by scrubbing an export,
|
|
840
|
+
it is achieved by **keeping every environment-specific value in a data store row and never in a
|
|
841
|
+
node** — then the export is publishable by construction. Verified on a real pack: the stored API
|
|
842
|
+
key value is absent from the bundle, and only placeholder/help text carries a hostname.
|
|
843
|
+
|
|
844
|
+
What DOES travel as author metadata: every resource keeps `createdBy` / `createdById` and the
|
|
845
|
+
source `workspaceId` in its metadata. Harmless for logic, but it means a published pack names its
|
|
846
|
+
author.
|
|
847
|
+
|
|
848
|
+
### Therefore: what a product must ship to be installable
|
|
849
|
+
|
|
850
|
+
Seeding cannot be left to the export. A pack needs a bootstrap flow that creates its own reference
|
|
851
|
+
data and its own settings KEYS with neutral defaults, because it will always land in empty stores.
|
|
852
|
+
Two rules learned from doing it wrong:
|
|
853
|
+
|
|
854
|
+
- **Seed identity and branding BLANK, seed only mechanics.** Buffers, notice periods and a UTC
|
|
855
|
+
default timezone are safe; a name, an address, a logo or a timezone taken from the author's own
|
|
856
|
+
install is a value the new owner has to discover and undo. A seed that hardcodes one region's
|
|
857
|
+
timezone into a weekly-availability table while the global default seeds as UTC is the
|
|
858
|
+
inconsistency this produces.
|
|
859
|
+
- **Seed what is deterministic.** Because form ids survive a transport, a setting that stores a
|
|
860
|
+
form id can be seeded as a literal instead of being left for the installer to look up. A
|
|
861
|
+
setting that a flow READS but that no screen can WRITE, left blank by the seed, is a silent
|
|
862
|
+
defect — the classic case is a cancellation link built from such a setting, which then goes out
|
|
863
|
+
in customer email pointing nowhere.
|
|
864
|
+
|
|
865
|
+
### Ship the credentials in the pack, and never hand-edit their secret fields
|
|
866
|
+
|
|
867
|
+
Naming credentials in the export changes the install from "rebuild and rewire" to "fill in the
|
|
868
|
+
blanks", and it does it without shipping a single secret:
|
|
869
|
+
|
|
870
|
+
- The credential RECORDS travel **with their original gids**, so every node parameter that points
|
|
871
|
+
at one resolves in the new workspace. The 11-node rewiring job disappears.
|
|
872
|
+
- With sensitive data OFF (the default), every designated secret field arrives **empty** while all
|
|
873
|
+
the non-secret configuration is kept: base URL, port, encryption mode, username, scopes, the
|
|
874
|
+
auth method, the header name, the test endpoint. The installer opens each credential and fills
|
|
875
|
+
only what is blank.
|
|
876
|
+
- Verified on a real pack: the stored API key value is absent from the bundle even though the
|
|
877
|
+
credential that holds it is in it.
|
|
878
|
+
|
|
879
|
+
**Do not write a placeholder into those empty fields.** It is the obvious instinct - make the
|
|
880
|
+
blanks visible as `[Replace_me]` - and it silently breaks the pack: on import the credential is
|
|
881
|
+
**dropped with no error and no mention**, the nodes that referenced it dangle again, and the only
|
|
882
|
+
symptom is a credential missing from a list nobody thought to re-count. Measured: the untouched
|
|
883
|
+
export imported 3 of 3; the same export with a placeholder typed into two secret fields imported 1
|
|
884
|
+
of 3. A valid-base64 value was dropped too, so it is not a formatting problem - treat the field as
|
|
885
|
+
an opaque slot that only the platform may fill. Ship the file exactly as exported.
|
|
886
|
+
|
|
887
|
+
What still needs cleaning by hand, at the SOURCE, before publishing: a credential's non-secret
|
|
888
|
+
fields are plaintext and are author-written, so anything personal typed into one travels. A test
|
|
889
|
+
endpoint naming a real mailbox is the usual case. Fix it in the credential, not in the export.
|
|
890
|
+
|
|
891
|
+
### An error port cannot go just anywhere: only a Join converges
|
|
892
|
+
|
|
893
|
+
Routing a fault away from the flow's failure path needs a target, and the platform rejects almost
|
|
894
|
+
every obvious one. Both refusals come from the runtime validator, so they are caught before a PUT
|
|
895
|
+
rather than discovered later:
|
|
896
|
+
|
|
897
|
+
| Target | Verdict |
|
|
898
|
+
| --- | --- |
|
|
899
|
+
| the node's own successor | `Duplicate connection port! SourceId:… DestinationId:…` - source+destination is the unique key, and the normal edge already occupies it |
|
|
900
|
+
| any node that already has one inbound edge | `statusCode 383, Action has too many input ports` - this includes Stop |
|
|
901
|
+
| a **Join** inserted after the successor | accepted |
|
|
902
|
+
|
|
903
|
+
So the working shape is: insert a Join between the successor and whatever came next, then point the
|
|
904
|
+
error port at the Join. The node that would have consumed the response simply does not run on the
|
|
905
|
+
fault path, its output variable stays null, and the flow reaches Stop at status 50. That converts
|
|
906
|
+
"the whole run failed" into "one section is empty", which is the difference between a page that
|
|
907
|
+
cannot open and a page that opens with one dropdown blank.
|
|
908
|
+
|
|
909
|
+
Worth designing for deliberately: the consumer node should already tolerate a null input (`const
|
|
910
|
+
res = <%0%> || {}`), because on the error path that is exactly what it gets - and if it also checks
|
|
911
|
+
the HTTP status it keeps working for the OTHER failure mode, an API that answers 401 rather than
|
|
912
|
+
faulting. A Call API that returns an error STATUS does not take the error port at all; only a fault
|
|
913
|
+
while building the input model does (a missing or unresolvable credential). Both need handling and
|
|
914
|
+
they are not the same path.
|
|
915
|
+
|
|
916
|
+
### A form has no address until a CustomUrl exists
|
|
917
|
+
|
|
918
|
+
Measured against the live forms host, which serves an SPA shell (and therefore HTTP 200) for every
|
|
919
|
+
path - so a status code proves nothing here and the rendered page has to be read:
|
|
920
|
+
|
|
921
|
+
| URL form | Result |
|
|
922
|
+
| --- | --- |
|
|
923
|
+
| `{forms_base}/{masterSlug}/{workspaceSlug}/{entitySlug}` | the form renders |
|
|
924
|
+
| `{forms_base}/{tinyUrl}` | the form renders |
|
|
925
|
+
| `{forms_base}/forms/{formId}` | **"Form not found"** |
|
|
926
|
+
| `{forms_base}/{formId}` | **"Form not found"** |
|
|
927
|
+
|
|
928
|
+
A CustomUrl is what mints the tinyUrl, it is per workspace and per entity, and it does not travel
|
|
929
|
+
in a transport. So an imported form is reachable at no address at all until someone creates one -
|
|
930
|
+
and any link the product BUILDS from a form id is dead. A fallback chain that ends in
|
|
931
|
+
`{base}/forms/{id}` looks like a safety net and is a dead link in a customer's email; leave the
|
|
932
|
+
link out instead.
|
|
933
|
+
|
|
934
|
+
### A seeded setting defeats COALESCE, because '' is not NULL
|
|
935
|
+
|
|
936
|
+
A bootstrap that creates its settings rows with empty defaults will quietly disable every
|
|
937
|
+
SQL fallback chain written over them: `COALESCE(a, b, c)` returns the first NON-NULL value, the
|
|
938
|
+
seeded row exists with `''`, so the chain stops at the first branch and the two working fallbacks
|
|
939
|
+
behind it are unreachable. The symptom is a blank link in generated mail while the query looks
|
|
940
|
+
correct and the settings look present.
|
|
941
|
+
|
|
942
|
+
Write the chain as `COALESCE(NULLIF(a,''), …)`, and for a composed branch put the `NULLIF` on the
|
|
943
|
+
part that can be blank - `CONCAT` returns NULL when any argument is NULL, so
|
|
944
|
+
`CONCAT(base, '/', NULLIF(slug,''))` makes the whole branch fall through by itself. The same bug
|
|
945
|
+
does not exist in the JavaScript equivalent, because `||` treats `''` as falsy: a chain ported from
|
|
946
|
+
a script to SQL acquires it on the way.
|
|
947
|
+
|
|
948
|
+
### One `<%N%>` sequence spans ALL of a node's parameters, outputs included
|
|
949
|
+
|
|
950
|
+
A node does not number each parameter separately. A Query Store node's statement chips, its
|
|
951
|
+
parameters-map sources and its output bindings all draw from ONE sequence - in a live release step
|
|
952
|
+
the statement held 0-4, the map 5-7 and the Result-Count output 8. So adding two parameters to the
|
|
953
|
+
map moves the output binding to 10, and an output left reading `<%8%>` is written back to whatever
|
|
954
|
+
now holds that index: a flow that validates clean and quietly files its result in the wrong
|
|
955
|
+
variable.
|
|
956
|
+
|
|
957
|
+
Anything that edits one parameter of a node therefore has to renumber the whole node, in a defined
|
|
958
|
+
order (statement, then map, then the remaining placeholder-bearing parameters in their existing
|
|
959
|
+
index order). Two traps when writing that:
|
|
960
|
+
|
|
961
|
+
- **An `id` is only a placeholder index inside a `variable` list.** A parameters-map ROW carries
|
|
962
|
+
its own ordinal `id` (0, 1, 2 …) which collides with the low indices; renumbering those turns
|
|
963
|
+
the map into nonsense.
|
|
964
|
+
- **A source's resolved ATTRIBUTE path cannot be re-derived from a name** without the model the
|
|
965
|
+
editor never loaded, so a source being carried over should be copied verbatim rather than
|
|
966
|
+
rebuilt. That is why `node-set-query --params` takes `{"keep": true}`.
|
|
967
|
+
|
|
968
|
+
### A timezone belongs to the reader, availability belongs to the owner
|
|
969
|
+
|
|
970
|
+
Worth stating because the natural implementation gets it half right. In a booking product the
|
|
971
|
+
window maths MUST run in the owner's zone - that is where "available 09:00 to 17:00" is defined -
|
|
972
|
+
while every label a visitor reads must be the visitor's. Those are different answers from the same
|
|
973
|
+
instant, and the instant is the only thing both sides agree on.
|
|
974
|
+
|
|
975
|
+
So a slot is correctly described by its UTC instant plus BOTH renderings, and a consumer picks.
|
|
976
|
+
The failure mode to avoid is an output that carries the owner's wall clock under a field name that
|
|
977
|
+
sounds like the reader's, because a page which trusts that name then shows a visitor in another
|
|
978
|
+
country times that are off by the offset while labelling them as local. Keep the owner's fields,
|
|
979
|
+
add the reader's, and name both for whose clock they are.
|
|
980
|
+
|
|
981
|
+
### Declaring a calendar event in the invitee's own zone
|
|
982
|
+
|
|
983
|
+
A timed event carries both an instant and a zone NAME, and they answer different questions. With
|
|
984
|
+
`dateTime` written as UTC the instant is already unambiguous, so adding
|
|
985
|
+
`start.timeZone` / `end.timeZone` moves nothing: it changes only which zone the calendar NAMES
|
|
986
|
+
when it renders the event. That matters because an invitation mail is rendered in the event's
|
|
987
|
+
zone, so an invitee who picked a time in their own zone otherwise reads it back in the host's and
|
|
988
|
+
concludes the booking went in wrong.
|
|
989
|
+
|
|
990
|
+
Two things to get right, both learned by breaking them:
|
|
991
|
+
|
|
992
|
+
- **Never let that field reach the API empty.** An empty zone is rejected, and the column feeding
|
|
993
|
+
it is exactly the one a record written by something other than the form may not have. Make the
|
|
994
|
+
query yield a valid zone unconditionally (`COALESCE(NULLIF(col,''), 'UTC')`); UTC is always a
|
|
995
|
+
real zone and leaves the instant alone.
|
|
996
|
+
- **A value only reaches the body if the loop item's MODEL declares it.** A query can select a
|
|
997
|
+
column, and the row will still not carry it unless the item's data model has an attribute of
|
|
998
|
+
that name - so the model attribute comes first, then the column, then the body reference. Adding
|
|
999
|
+
an attribute is additive and leaves existing attribute ids alone (verified), which is what makes
|
|
1000
|
+
this safe to do to a model a live flow is iterating.
|
|
1001
|
+
|
|
1002
|
+
The host's own calendar view is unaffected either way, because a calendar renders events in the
|
|
1003
|
+
VIEWER's zone; only the stored zone name and the mails generated from it change.
|
|
1004
|
+
|
|
1005
|
+
### A form publishes only TOP-LEVEL variables: a data-model input never arrives
|
|
1006
|
+
|
|
1007
|
+
The hardest fault to see in a form-driven panel, because every layer reports success and the
|
|
1008
|
+
mapping looks right in the designer.
|
|
1009
|
+
|
|
1010
|
+
A `RUN_PROCESS` event can map a form field onto an **attribute of a data-model variable**
|
|
1011
|
+
(`Row.Name`, `Row.DurationMinutes`, ...). The designer accepts it, the left side resolves to a real
|
|
1012
|
+
attribute, the flow validates, and the map reads correctly when you print it back. At runtime the
|
|
1013
|
+
browser does not send it. The publish call carries only the process's **top-level** variables; every
|
|
1014
|
+
attribute-path entry is dropped, so the whole model variable arrives NULL.
|
|
1015
|
+
|
|
1016
|
+
Why it is so hard to attribute:
|
|
1017
|
+
|
|
1018
|
+
- The process looks healthy. Called with a JSON payload through the run endpoint, the same model
|
|
1019
|
+
input works perfectly, so every API-side test passes. Only the browser path fails, which is why
|
|
1020
|
+
"the process runs but the page does not work" is the honest description of the symptom - and the
|
|
1021
|
+
reason to insist on testing through the page rather than through the process.
|
|
1022
|
+
- A guard hides it. A sane statement checks its inputs, so the write is skipped rather than
|
|
1023
|
+
failing: the run ends successfully with an affected-row count of 0 and no error. The page then
|
|
1024
|
+
reports its own generic failure, which points at the page.
|
|
1025
|
+
- Removing the guard diagnostically finally speaks, but it accuses the wrong parameter: the write
|
|
1026
|
+
fails on whichever NOT NULL column it reaches first, so the fault reads as "one field does not
|
|
1027
|
+
arrive" when in fact none of them do. Do not conclude from one named column; check every
|
|
1028
|
+
parameter sourced from the same variable.
|
|
1029
|
+
- Nothing in the attribute's own type matters. The attributes that appear to work are the ones a
|
|
1030
|
+
guard does not test, not the ones with a convenient type. Retyping an attribute is a dead end.
|
|
1031
|
+
|
|
1032
|
+
**How to see it in one step.** Install a tiny interceptor over `fetch` and `XMLHttpRequest.send`
|
|
1033
|
+
in the page before clicking, recording the body of every request whose URL looks like a publish or
|
|
1034
|
+
launch, then click the control for real and read what was recorded. The publish body is a flat list
|
|
1035
|
+
of `{id, value}` pairs, one per variable the form actually sends. Compare those ids against the
|
|
1036
|
+
process's variables: whatever is missing is what never left the browser. This is worth reaching for
|
|
1037
|
+
early on any "the page says it failed but the process is fine" report, because it replaces a chain
|
|
1038
|
+
of inference with one measurement.
|
|
1039
|
+
|
|
1040
|
+
**The fix, and the convention.** Give the process **flat, top-level** input variables - one per
|
|
1041
|
+
field - and bind the statement's parameters to those. Declare them String and coerce in SQL, since
|
|
1042
|
+
a panel's values are text on the wire anyway (and the id of an existing record arrives as a JSON
|
|
1043
|
+
number, not a string, so a cast is needed regardless). Rebuild the event map to the flat variables
|
|
1044
|
+
and the same click starts working with no other change.
|
|
1045
|
+
|
|
1046
|
+
A data model is still the right shape for a value passed **between processes**, or for a list a
|
|
1047
|
+
process returns. The restriction is specific to what a form publishes inward.
|
|
1048
|
+
|
|
1049
|
+
**Worth checking as a one-pass audit** rather than a click at a time: list every process the form
|
|
1050
|
+
calls, expand each input variable, and flag any that is a data model rather than a primitive. If
|
|
1051
|
+
one panel is broken and the others are not, this difference alone usually explains it - and the
|
|
1052
|
+
working panels show the convention the broken one should follow.
|
|
1053
|
+
|
|
1054
|
+
A related restriction has the same flavour and the same cause: a control added to a table row
|
|
1055
|
+
through the API is not part of that row's own field model, so its value path reads nothing and has
|
|
1056
|
+
to be carried to a plain field before a save can see it.
|
|
1057
|
+
|
|
1058
|
+
### A date picker hands back an INSTANT, not a day
|
|
1059
|
+
|
|
1060
|
+
The control the visitor clicks a day on does not store that day. It stores local midnight of
|
|
1061
|
+
it, and what travels to the server is that moment in UTC. For every zone east of Greenwich
|
|
1062
|
+
the UTC calendar day is then the day BEFORE the one that was clicked, so the oldest trick in
|
|
1063
|
+
the book - taking the first ten characters of the ISO string - silently reads the wrong day.
|
|
1064
|
+
|
|
1065
|
+
It hides well because it is not a crash and not even always visible. The page moves one day
|
|
1066
|
+
back; when that earlier day happens to be a valid choice it is simply shown instead, and the
|
|
1067
|
+
report that comes back is "my selection resets when I change something else" rather than
|
|
1068
|
+
"the date is off by one". West of Greenwich the same code is correct, so whoever wrote it
|
|
1069
|
+
may never have seen it fail.
|
|
1070
|
+
|
|
1071
|
+
Convert the instant in the zone the picker used, which is the VISITOR's zone, not the
|
|
1072
|
+
organisation's:
|
|
1073
|
+
|
|
1074
|
+
```js
|
|
1075
|
+
new Intl.DateTimeFormat('en-GB', { timeZone: zone, year: 'numeric', month: '2-digit', day: '2-digit' })
|
|
1076
|
+
.formatToParts(new Date(Date.parse(value)))
|
|
1077
|
+
```
|
|
1078
|
+
|
|
1079
|
+
A page that shows times to a visitor already detects that zone for its own labels, so it is
|
|
1080
|
+
usually available to send alongside the date rather than something new to obtain. Keep the
|
|
1081
|
+
bare-day case first (a value that is already `YYYY-MM-DD` carries no instant and must not be
|
|
1082
|
+
shifted), and fall back to the raw slice inside a `catch` so a missing timezone database
|
|
1083
|
+
degrades to the old behaviour instead of dropping the choice entirely.
|
|
1084
|
+
|
|
1085
|
+
Worth testing explicitly in both directions, because one direction passes by luck: the same
|
|
1086
|
+
instant must resolve to different days under an eastern and a western zone. If it does not,
|
|
1087
|
+
the zone argument is being ignored and the conversion only appeared to work.
|
|
1088
|
+
|
|
1089
|
+
### Adding a binding to a node: take the next FREE index, not the next one
|
|
1090
|
+
|
|
1091
|
+
A consequence of one `<%N%>` sequence spanning all of a node's parameters, outputs included,
|
|
1092
|
+
and the thing that makes adding a binding look harder than it is. A script using `<%0%>`
|
|
1093
|
+
through `<%2%>` whose node also has two output bindings is already using indices 3 and 4, so
|
|
1094
|
+
introducing `<%3%>` collides with an output and the edit has to renumber the whole node.
|
|
1095
|
+
|
|
1096
|
+
It does not have to. The indices identify bindings, they are not required to be contiguous
|
|
1097
|
+
per parameter or to follow reading order, so the new placeholder can simply take the next
|
|
1098
|
+
index free across the WHOLE node. The script then reads `<%0%>`, `<%1%>`, `<%2%>`, `<%5%>`,
|
|
1099
|
+
which looks odd and is correct, and no existing binding moves. Read every parameter of the
|
|
1100
|
+
node before choosing the number; the outputs are the ones that get forgotten.
|