@a-company/paradigm 5.38.0 → 6.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{accept-orchestration-OATWIRHP.js → accept-orchestration-QQISPINV.js} +1 -1
- package/dist/add-UOR4INIV.js +8 -0
- package/dist/{agent-loader-RIVI6QPP.js → agent-loader-2WJHD46U.js} +1 -1
- package/dist/{agent-loader-RJRVO5GQ.js → agent-loader-YKS2PQWO.js} +1 -1
- package/dist/{ambient-76YMUA5Q.js → ambient-BE3SQXNN.js} +1 -1
- package/dist/{ambient-WTLYUAQM.js → ambient-NVKQCW2A.js} +12 -12
- package/dist/{assess-UFPYEJKP.js → assess-63WXHWJV.js} +1 -1
- package/dist/{calibration-OLJYB5HN.js → calibration-BDHGYJOK.js} +1 -1
- package/dist/{chunk-5QOCKWK5.js → chunk-4PSD5R7N.js} +2 -2
- package/dist/{chunk-HOBHJPTL.js → chunk-6SKSV5B2.js} +1 -1
- package/dist/{chunk-4L7665QV.js → chunk-FEYOQMZ5.js} +1 -1
- package/dist/{chunk-NEJ4ZLCY.js → chunk-GAFKOFAV.js} +1 -1
- package/dist/chunk-GRZQIKST.js +2 -0
- package/dist/{chunk-RLCH7DXQ.js → chunk-K7X3Z3GL.js} +1 -1
- package/dist/{chunk-4VKSEOXZ.js → chunk-LPBCQM5Y.js} +3 -3
- package/dist/{chunk-74SGKSRQ.js → chunk-M2HKWR25.js} +1 -1
- package/dist/{chunk-BOYQAMGC.js → chunk-M3PPXJU4.js} +1 -1
- package/dist/chunk-PHEX6LU4.js +111 -0
- package/dist/chunk-Q527BPUF.js +2 -0
- package/dist/chunk-R5ECMBIV.js +11 -0
- package/dist/{chunk-X3U3IGYT.js → chunk-TBWWFRL5.js} +1 -1
- package/dist/{chunk-MQIG6SMF.js → chunk-TNVWGPCE.js} +1 -1
- package/dist/chunk-TZDYIPVU.js +521 -0
- package/dist/{chunk-3XGNXXCT.js → chunk-UZ5H7K6Q.js} +1 -1
- package/dist/chunk-VIG5LSGZ.js +2 -0
- package/dist/chunk-VNIX5KBT.js +3 -0
- package/dist/{chunk-AGFPVSX5.js → chunk-VXIIVMTM.js} +1 -1
- package/dist/{chunk-ORDKEGII.js → chunk-WESTEMIM.js} +1 -1
- package/dist/{chunk-DOCDDDTD.js → chunk-YNDPSWOE.js} +5 -5
- package/dist/chunk-Z5QW6USC.js +2 -0
- package/dist/{compliance-D7GD6ZYC.js → compliance-BNFWQPKM.js} +1 -1
- package/dist/config-schema-FLHRVZMI.js +2 -0
- package/dist/{context-audit-XRPT3OU2.js → context-audit-JVCA6GSV.js} +1 -1
- package/dist/{cursorrules-U5O4G5T4.js → cursorrules-ZXPXPZ3P.js} +1 -1
- package/dist/decision-loader-HELL2AMX.js +2 -0
- package/dist/{delete-P5VULXR4.js → delete-2C6ALLYY.js} +1 -1
- package/dist/{diff-YGHBIJY5.js → diff-MF55KQZH.js} +1 -1
- package/dist/{dist-KGRCLBJP-2QAPFYNF.js → dist-GQ42YS5N-4HIJZVBB.js} +10 -10
- package/dist/{docs-USDAF26F.js → docs-O37YLLRN.js} +1 -1
- package/dist/doctor-IG5XM4C4.js +2 -0
- package/dist/{edit-GUU3HBVW.js → edit-P3MDAZLU.js} +1 -1
- package/dist/{flow-FVZR3YJ4.js → flow-BGXOVE2V.js} +1 -1
- package/dist/index.js +6 -6
- package/dist/init-M44SO65G.js +2 -0
- package/dist/{init-XYB62Q3X.js → init-V4KSEKPK.js} +1 -1
- package/dist/{list-YKIQNKGB.js → list-2XIWUEMA.js} +1 -1
- package/dist/list-CFHINXIS.js +12 -0
- package/dist/lore-loader-D2ISOASW.js +2 -0
- package/dist/lore-loader-PXFKMKAN.js +2 -0
- package/dist/mcp.js +4 -4
- package/dist/metrics-UESGUHTA.js +2 -0
- package/dist/migrate-assessments-YSITX7KM.js +4 -0
- package/dist/migrate-decisions-NPLQOEEH.js +6 -0
- package/dist/migrate-plsat-EM2ACIQ3.js +6 -0
- package/dist/{nomination-engine-EALA5MGI.js → nomination-engine-QPZJH6XO.js} +1 -1
- package/dist/{notebook-loader-PXNRBBXD.js → notebook-loader-3J2OFMS3.js} +1 -1
- package/dist/{orchestrate-M5PBZBJQ.js → orchestrate-RID7HHHH.js} +1 -1
- package/dist/{platform-server-DNAMH4YI.js → platform-server-UD45NTGV.js} +1 -1
- package/dist/{portal-check-ZMLVBIGW.js → portal-check-DV2VSJ5E.js} +1 -1
- package/dist/portal-compliance-JONQ4SOP.js +2 -0
- package/dist/{probe-3FTG6LYO.js → probe-5HAXULAD.js} +1 -1
- package/dist/{providers-AWA7WLLM.js → providers-4PXMWA7V.js} +1 -1
- package/dist/quiz-WYIZJG5K.js +10 -0
- package/dist/{record-YXPB34MY.js → record-N3VNYYKJ.js} +1 -1
- package/dist/reindex-FWPD2VGM.js +2 -0
- package/dist/{retag-N5XF3KXP.js → retag-72R2OSZV.js} +1 -1
- package/dist/{review-77QI6VOC.js → review-2INNWLTW.js} +1 -1
- package/dist/{sentinel-HYAZ3CO5.js → sentinel-EFPEX246.js} +1 -1
- package/dist/{sentinel-bridge-VR357PKL.js → sentinel-bridge-UR2MKARY.js} +1 -1
- package/dist/{serve-U47GULB6.js → serve-MO35XIZE.js} +1 -1
- package/dist/serve-OQYUO7CR.js +12 -0
- package/dist/{server-4YNUIK4W.js → server-4D77LCST.js} +1 -1
- package/dist/server-FGUL2FWQ.js +7 -0
- package/dist/session-tracker-KGORN6B5.js +2 -0
- package/dist/{session-work-log-PAKXOFGL.js → session-work-log-4IEVE4KK.js} +1 -1
- package/dist/{session-work-log-ZP45TREI.js → session-work-log-EE4UIZ33.js} +1 -1
- package/dist/{setup-FEWSYS3Y.js → setup-ZSEC72BS.js} +1 -1
- package/dist/{shift-PC6C7NUX.js → shift-TVNY2CQF.js} +6 -6
- package/dist/{show-PJ5LFLIL.js → show-JH7LJ5MT.js} +1 -1
- package/dist/show-WVHAL4VU.js +7 -0
- package/dist/{spawn-M5BAV252.js → spawn-UH5RENSE.js} +1 -1
- package/dist/status-S7Z5FVIE.js +6 -0
- package/dist/{summary-PYTEIJ4U.js → summary-WLI3NF4G.js} +2 -2
- package/dist/{sweep-HU74OPVW.js → sweep-7TZFN5NS.js} +1 -1
- package/dist/sync-55U6QPIA.js +2 -0
- package/dist/{sync-llms-7CAI74QL.js → sync-llms-GF7DDQDI.js} +1 -1
- package/dist/{team-PDK64JXI.js → team-MGT66HZQ.js} +1 -1
- package/dist/{timeline-K3ZFKJ3R.js → timeline-RK7O2SCM.js} +1 -1
- package/dist/tools-QJHAVYI6.js +2 -0
- package/dist/university-content/notes/N-para-001-build-something.md +126 -0
- package/dist/university-content/notes/N-para-001-meet-the-team.md +85 -0
- package/dist/university-content/notes/N-para-001-shift-setup.md +74 -0
- package/dist/university-content/notes/N-para-101-component-types.md +99 -0
- package/dist/university-content/notes/N-para-101-first-steps.md +134 -0
- package/dist/university-content/notes/N-para-101-five-symbols.md +128 -0
- package/dist/university-content/notes/N-para-101-paradigm-logger.md +89 -0
- package/dist/university-content/notes/N-para-101-portal-yaml.md +112 -0
- package/dist/university-content/notes/N-para-101-project-structure.md +143 -0
- package/dist/university-content/notes/N-para-101-purpose-files.md +121 -0
- package/dist/university-content/notes/N-para-101-tags-and-classification.md +93 -0
- package/dist/university-content/notes/N-para-101-welcome.md +51 -0
- package/dist/university-content/notes/N-para-201-architecture-review.md +175 -0
- package/dist/university-content/notes/N-para-201-aspect-graph.md +79 -0
- package/dist/university-content/notes/N-para-201-aspects-and-anchors.md +112 -0
- package/dist/university-content/notes/N-para-201-component-patterns.md +138 -0
- package/dist/university-content/notes/N-para-201-cross-cutting-concerns.md +145 -0
- package/dist/university-content/notes/N-para-201-disciplines.md +187 -0
- package/dist/university-content/notes/N-para-201-flows-deep-dive.md +119 -0
- package/dist/university-content/notes/N-para-201-gates-deep-dive.md +165 -0
- package/dist/university-content/notes/N-para-201-portal-protocol.md +133 -0
- package/dist/university-content/notes/N-para-201-signal-patterns.md +159 -0
- package/dist/university-content/notes/N-para-201-symbol-naming.md +149 -0
- package/dist/university-content/notes/N-para-301-context-management.md +53 -0
- package/dist/university-content/notes/N-para-301-decisions.md +99 -0
- package/dist/university-content/notes/N-para-301-doctor-and-validation.md +70 -0
- package/dist/university-content/notes/N-para-301-enforcement-levels.md +102 -0
- package/dist/university-content/notes/N-para-301-fragility-tracking.md +50 -0
- package/dist/university-content/notes/N-para-301-history-system.md +42 -0
- package/dist/university-content/notes/N-para-301-navigation-system.md +55 -0
- package/dist/university-content/notes/N-para-301-operations-review.md +55 -0
- package/dist/university-content/notes/N-para-301-paradigm-shift.md +93 -0
- package/dist/university-content/notes/N-para-301-protocols.md +113 -0
- package/dist/university-content/notes/N-para-301-ripple-analysis.md +53 -0
- package/dist/university-content/notes/N-para-301-sentinel-observability.md +87 -0
- package/dist/university-content/notes/N-para-301-sync-and-maintenance.md +57 -0
- package/dist/university-content/notes/N-para-301-wisdom-system.md +89 -0
- package/dist/university-content/notes/N-para-401-agent-identity.md +99 -0
- package/dist/university-content/notes/N-para-401-agent-interop.md +87 -0
- package/dist/university-content/notes/N-para-401-agent-roles.md +107 -0
- package/dist/university-content/notes/N-para-401-commit-conventions.md +82 -0
- package/dist/university-content/notes/N-para-401-mastery-review.md +71 -0
- package/dist/university-content/notes/N-para-401-mcp-tools-overview.md +102 -0
- package/dist/university-content/notes/N-para-401-multi-agent-coordination.md +80 -0
- package/dist/university-content/notes/N-para-401-notebooks-permissions.md +66 -0
- package/dist/university-content/notes/N-para-401-orchestration-workflow.md +101 -0
- package/dist/university-content/notes/N-para-401-pm-governance.md +71 -0
- package/dist/university-content/notes/N-para-401-provider-cascade.md +75 -0
- package/dist/university-content/notes/N-para-401-quick-check.md +95 -0
- package/dist/university-content/notes/N-para-501-advanced-workflows.md +122 -0
- package/dist/university-content/notes/N-para-501-aspect-graph-advanced.md +195 -0
- package/dist/university-content/notes/N-para-501-aspect-graph-internals.md +97 -0
- package/dist/university-content/notes/N-para-501-assessment-loops.md +116 -0
- package/dist/university-content/notes/N-para-501-conductor-workspace.md +77 -0
- package/dist/university-content/notes/N-para-501-habits-practice.md +164 -0
- package/dist/university-content/notes/N-para-501-hook-enforcement.md +100 -0
- package/dist/university-content/notes/N-para-501-lore-system.md +155 -0
- package/dist/university-content/notes/N-para-501-platform-agent-ui.md +108 -0
- package/dist/university-content/notes/N-para-501-review-compliance.md +72 -0
- package/dist/university-content/notes/N-para-501-sentinel-deep-dive.md +173 -0
- package/dist/university-content/notes/N-para-501-session-intelligence.md +104 -0
- package/dist/university-content/notes/N-para-501-symphony-a-mail.md +120 -0
- package/dist/university-content/notes/N-para-501-symphony-networking.md +119 -0
- package/dist/university-content/notes/N-para-501-task-management.md +100 -0
- package/dist/university-content/notes/N-para-601-agent-renaissance.md +121 -0
- package/dist/university-content/notes/N-para-601-attention-scoring.md +129 -0
- package/dist/university-content/notes/N-para-601-context-composition.md +146 -0
- package/dist/university-content/notes/N-para-601-data-sovereignty.md +140 -0
- package/dist/university-content/notes/N-para-601-event-stream.md +126 -0
- package/dist/university-content/notes/N-para-601-knowledge-streams.md +144 -0
- package/dist/university-content/notes/N-para-601-learning-loop.md +68 -0
- package/dist/university-content/notes/N-para-601-maestro-team-collab.md +136 -0
- package/dist/university-content/notes/N-para-601-nominations-debates.md +115 -0
- package/dist/university-content/notes/N-para-701-agent-notebooks.md +131 -0
- package/dist/university-content/notes/N-para-701-agent-pods-nevrland.md +182 -0
- package/dist/university-content/notes/N-para-701-agent-profiles.md +197 -0
- package/dist/university-content/notes/N-para-701-agent-roster.md +82 -0
- package/dist/university-content/notes/N-para-701-agent-state.md +180 -0
- package/dist/university-content/notes/N-para-701-learning-feedback-loop.md +188 -0
- package/dist/university-content/notes/N-para-701-model-tier-resolution.md +204 -0
- package/dist/university-content/notes/N-para-701-orchestration-enforcement.md +169 -0
- package/dist/university-content/notes/N-para-701-per-project-rosters.md +198 -0
- package/dist/university-content/notes/N-para-701-symphony-visibility.md +142 -0
- package/dist/university-content/paths/LP-para-001.yaml +29 -0
- package/dist/university-content/paths/LP-para-101.yaml +59 -0
- package/dist/university-content/paths/LP-para-201.yaml +69 -0
- package/dist/university-content/paths/LP-para-301.yaml +84 -0
- package/dist/university-content/paths/LP-para-401.yaml +74 -0
- package/dist/university-content/paths/LP-para-501.yaml +89 -0
- package/dist/university-content/paths/LP-para-601.yaml +59 -0
- package/dist/university-content/paths/LP-para-701.yaml +64 -0
- package/dist/university-content/quizzes/Q-para-001-build-something.yaml +46 -0
- package/dist/university-content/quizzes/Q-para-001-meet-the-team.yaml +46 -0
- package/dist/university-content/quizzes/Q-para-001-shift-setup.yaml +46 -0
- package/dist/university-content/quizzes/Q-para-101-component-types.yaml +46 -0
- package/dist/university-content/quizzes/Q-para-101-first-steps.yaml +56 -0
- package/dist/university-content/quizzes/Q-para-101-five-symbols.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-101-paradigm-logger.yaml +56 -0
- package/dist/university-content/quizzes/Q-para-101-portal-yaml.yaml +56 -0
- package/dist/university-content/quizzes/Q-para-101-project-structure.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-101-purpose-files.yaml +56 -0
- package/dist/university-content/quizzes/Q-para-101-tags-and-classification.yaml +56 -0
- package/dist/university-content/quizzes/Q-para-101-welcome.yaml +56 -0
- package/dist/university-content/quizzes/Q-para-201-architecture-review.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-201-aspect-graph.yaml +46 -0
- package/dist/university-content/quizzes/Q-para-201-aspects-and-anchors.yaml +56 -0
- package/dist/university-content/quizzes/Q-para-201-component-patterns.yaml +56 -0
- package/dist/university-content/quizzes/Q-para-201-cross-cutting-concerns.yaml +56 -0
- package/dist/university-content/quizzes/Q-para-201-disciplines.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-201-flows-deep-dive.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-201-gates-deep-dive.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-201-portal-protocol.yaml +56 -0
- package/dist/university-content/quizzes/Q-para-201-signal-patterns.yaml +56 -0
- package/dist/university-content/quizzes/Q-para-201-symbol-naming.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-301-context-management.yaml +56 -0
- package/dist/university-content/quizzes/Q-para-301-decisions.yaml +76 -0
- package/dist/university-content/quizzes/Q-para-301-doctor-and-validation.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-301-enforcement-levels.yaml +46 -0
- package/dist/university-content/quizzes/Q-para-301-fragility-tracking.yaml +46 -0
- package/dist/university-content/quizzes/Q-para-301-history-system.yaml +56 -0
- package/dist/university-content/quizzes/Q-para-301-navigation-system.yaml +56 -0
- package/dist/university-content/quizzes/Q-para-301-operations-review.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-301-paradigm-shift.yaml +46 -0
- package/dist/university-content/quizzes/Q-para-301-protocols.yaml +56 -0
- package/dist/university-content/quizzes/Q-para-301-ripple-analysis.yaml +56 -0
- package/dist/university-content/quizzes/Q-para-301-sentinel-observability.yaml +46 -0
- package/dist/university-content/quizzes/Q-para-301-sync-and-maintenance.yaml +46 -0
- package/dist/university-content/quizzes/Q-para-301-wisdom-system.yaml +56 -0
- package/dist/university-content/quizzes/Q-para-401-agent-identity.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-401-agent-interop.yaml +46 -0
- package/dist/university-content/quizzes/Q-para-401-agent-roles.yaml +56 -0
- package/dist/university-content/quizzes/Q-para-401-commit-conventions.yaml +56 -0
- package/dist/university-content/quizzes/Q-para-401-mastery-review.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-401-mcp-tools-overview.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-401-multi-agent-coordination.yaml +76 -0
- package/dist/university-content/quizzes/Q-para-401-notebooks-permissions.yaml +61 -0
- package/dist/university-content/quizzes/Q-para-401-orchestration-workflow.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-401-pm-governance.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-401-provider-cascade.yaml +56 -0
- package/dist/university-content/quizzes/Q-para-401-quick-check.yaml +46 -0
- package/dist/university-content/quizzes/Q-para-501-advanced-workflows.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-501-aspect-graph-advanced.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-501-aspect-graph-internals.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-501-assessment-loops.yaml +46 -0
- package/dist/university-content/quizzes/Q-para-501-conductor-workspace.yaml +46 -0
- package/dist/university-content/quizzes/Q-para-501-habits-practice.yaml +56 -0
- package/dist/university-content/quizzes/Q-para-501-hook-enforcement.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-501-lore-system.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-501-platform-agent-ui.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-501-review-compliance.yaml +61 -0
- package/dist/university-content/quizzes/Q-para-501-sentinel-deep-dive.yaml +86 -0
- package/dist/university-content/quizzes/Q-para-501-session-intelligence.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-501-symphony-a-mail.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-501-symphony-networking.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-501-task-management.yaml +46 -0
- package/dist/university-content/quizzes/Q-para-601-agent-renaissance.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-601-attention-scoring.yaml +56 -0
- package/dist/university-content/quizzes/Q-para-601-context-composition.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-601-data-sovereignty.yaml +56 -0
- package/dist/university-content/quizzes/Q-para-601-event-stream.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-601-knowledge-streams.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-601-learning-loop.yaml +56 -0
- package/dist/university-content/quizzes/Q-para-601-maestro-team-collab.yaml +86 -0
- package/dist/university-content/quizzes/Q-para-601-nominations-debates.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-701-agent-notebooks.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-701-agent-pods-nevrland.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-701-agent-profiles.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-701-agent-roster.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-701-agent-state.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-701-learning-feedback-loop.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-701-model-tier-resolution.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-701-orchestration-enforcement.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-701-per-project-rosters.yaml +66 -0
- package/dist/university-content/quizzes/Q-para-701-symphony-visibility.yaml +66 -0
- package/dist/university-content/quizzes/Q-plsat-v2.yaml +904 -0
- package/dist/university-content/quizzes/Q-plsat-v3.yaml +2909 -0
- package/dist/university-content/reference.json +2 -2
- package/dist/university-ui/assets/{index-CecQrfSn.js → index-nNgzO1il.js} +2 -2
- package/dist/university-ui/assets/{index-CecQrfSn.js.map → index-nNgzO1il.js.map} +1 -1
- package/dist/university-ui/index.html +1 -1
- package/dist/{upgrade-GX56QE3C.js → upgrade-NKN63VTY.js} +2 -2
- package/dist/validate-XUQZTF3H.js +9 -0
- package/dist/{watch-YCODNIET.js → watch-25GJHQYT.js} +1 -1
- package/lore-ui/dist/assets/{index-Bk-K0qgN.js → index-DKhNxgtW.js} +10 -10
- package/lore-ui/dist/index.html +1 -1
- package/package.json +2 -2
- package/platform-ui/dist/assets/{AmbientSection-BYjt75R1.js → AmbientSection-CwatqcBD.js} +1 -1
- package/platform-ui/dist/assets/{CanvasSection-rKvA_vZj.js → CanvasSection-dFAthehN.js} +1 -1
- package/platform-ui/dist/assets/{DocsSection-CI9K73M-.js → DocsSection-BZ2SFJBZ.js} +1 -1
- package/platform-ui/dist/assets/{GitSection-DSGj_c6S.js → GitSection-MNNYU1tO.js} +1 -1
- package/platform-ui/dist/assets/{GraphSection-CawN7pC5.js → GraphSection-COYjb4Pt.js} +1 -1
- package/platform-ui/dist/assets/LoreSection-B0hUbfsJ.js +1 -0
- package/platform-ui/dist/assets/{SentinelSection-DNgoYMH0.js → SentinelSection-BCxW1DCp.js} +1 -1
- package/platform-ui/dist/assets/{SymphonySection-C0zfcqv3.js → SymphonySection-BsucZRqy.js} +1 -1
- package/platform-ui/dist/assets/{TeamSection-Bzd3Dt9Q.js → TeamSection-C0QNTudW.js} +1 -1
- package/platform-ui/dist/assets/{UniversitySection-tBr62R0S.js → UniversitySection-DN1-g9pw.js} +1 -1
- package/platform-ui/dist/assets/{index-BaOmyn11.js → index-DwUT8pju.js} +2 -2
- package/platform-ui/dist/index.html +1 -1
- package/dist/add-P76GEMGF.js +0 -8
- package/dist/chunk-JQKKVAAN.js +0 -2
- package/dist/chunk-NQ47TA6C.js +0 -111
- package/dist/chunk-ODVKPZZ4.js +0 -2
- package/dist/chunk-Q2J542ST.js +0 -2
- package/dist/chunk-RBLK34IA.js +0 -11
- package/dist/chunk-RN4VE6P3.js +0 -521
- package/dist/chunk-WS2N27RX.js +0 -3
- package/dist/config-schema-GUQY2QN7.js +0 -2
- package/dist/decision-loader-2XPZE4EZ.js +0 -2
- package/dist/doctor-WMVULMQD.js +0 -2
- package/dist/list-5IUGP3ZB.js +0 -7
- package/dist/lore-loader-RVQI5GXL.js +0 -2
- package/dist/lore-loader-XY5MZRR2.js +0 -2
- package/dist/migrate-assessments-GEI5WMI2.js +0 -4
- package/dist/portal-compliance-6YR27IQU.js +0 -2
- package/dist/quiz-FE5UGAY2.js +0 -10
- package/dist/reindex-I6LPAKCC.js +0 -2
- package/dist/serve-OY6XYL7F.js +0 -12
- package/dist/server-2MNROHF6.js +0 -7
- package/dist/session-tracker-MWJAJA6Z.js +0 -2
- package/dist/show-BOAVWZPZ.js +0 -7
- package/dist/status-A37ECYNJ.js +0 -6
- package/dist/sync-DLUBV5HQ.js +0 -2
- package/dist/tools-5ITPEPSV.js +0 -2
- package/dist/university-content/courses/.purpose +0 -492
- package/dist/university-content/courses/para-001.json +0 -166
- package/dist/university-content/courses/para-101.json +0 -615
- package/dist/university-content/courses/para-201.json +0 -794
- package/dist/university-content/courses/para-301.json +0 -830
- package/dist/university-content/courses/para-401.json +0 -868
- package/dist/university-content/courses/para-501.json +0 -1166
- package/dist/university-content/courses/para-601.json +0 -719
- package/dist/university-content/courses/para-701.json +0 -807
- package/dist/university-content/plsat/.purpose +0 -162
- package/dist/university-content/plsat/v2.0.json +0 -760
- package/dist/university-content/plsat/v3.0.json +0 -3453
- package/dist/validate-C6SMKGYD.js +0 -9
- package/platform-ui/dist/assets/LoreSection-oO5dCe6O.js +0 -1
- /package/dist/{chunk-BV5PRPLB.js → chunk-IZSBGW6E.js} +0 -0
- /package/templates/paradigm/specs/{scan.md → probe.md} +0 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: N-para-201-flows-deep-dive
|
|
3
|
+
title: Flows in Depth
|
|
4
|
+
type: note
|
|
5
|
+
author: paradigm
|
|
6
|
+
created: '2026-04-22'
|
|
7
|
+
updated: '2026-04-22'
|
|
8
|
+
tags:
|
|
9
|
+
- course
|
|
10
|
+
- para-201
|
|
11
|
+
- create-flows-when
|
|
12
|
+
- steps-are-component
|
|
13
|
+
- define-flows-in
|
|
14
|
+
symbols: []
|
|
15
|
+
difficulty: beginner
|
|
16
|
+
estimatedMinutes: 4
|
|
17
|
+
prerequisites: []
|
|
18
|
+
category: paradigm-core
|
|
19
|
+
origin: imported
|
|
20
|
+
source: courses/para-201.json
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## When to Create a Flow
|
|
24
|
+
|
|
25
|
+
Not every process needs a `$flow`. The rule of thumb is: **create a flow when logic spans three or more components in a specific order**. A two-component interaction (service A calls service B) is simple enough to document in the component's `.purpose` entry. But once a third component enters the picture — and the order matters — a flow captures the choreography that no single component can describe.
|
|
26
|
+
|
|
27
|
+
Consider these scenarios:
|
|
28
|
+
- User clicks "Buy" → cart validates → payment charges → order creates → email sends. That is four components in sequence. This needs a `$checkout-flow`.
|
|
29
|
+
- A cron job triggers → data fetches → report generates → file uploads → Slack notifies. Five components. This needs a `$daily-report-flow`.
|
|
30
|
+
- A controller calls a service which returns data. Two components, no sequence ambiguity. This does NOT need a flow.
|
|
31
|
+
|
|
32
|
+
## Flow Step Structure
|
|
33
|
+
|
|
34
|
+
Each step in a flow is a `component + action` pair. The component references a `#component` defined in a `.purpose` file, and the action describes what that component does in this step:
|
|
35
|
+
|
|
36
|
+
```yaml
|
|
37
|
+
flows:
|
|
38
|
+
$onboarding:
|
|
39
|
+
description: New user setup from registration to first project
|
|
40
|
+
steps:
|
|
41
|
+
- component: "#auth-handler"
|
|
42
|
+
action: create-account
|
|
43
|
+
description: Validates email, hashes password, creates user record
|
|
44
|
+
- component: "#email-service"
|
|
45
|
+
action: send-welcome
|
|
46
|
+
description: Sends welcome email with verification link
|
|
47
|
+
- component: "#project-service"
|
|
48
|
+
action: create-default-project
|
|
49
|
+
description: Creates a starter project for the new user
|
|
50
|
+
- component: "#notification-service"
|
|
51
|
+
action: notify-team
|
|
52
|
+
description: Alerts the team Slack channel about the new signup
|
|
53
|
+
signals: ["!user-created", "!welcome-email-sent"]
|
|
54
|
+
gates: []
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The `description` on each step is optional but valuable — it tells AI agents what happens at each point without reading the source code.
|
|
58
|
+
|
|
59
|
+
## Documenting Flows in .purpose Files
|
|
60
|
+
|
|
61
|
+
Flows are defined in the `flows` section of a `.purpose` file, usually in the directory of the *initiating* component. If the checkout flow starts in the cart module, define `$checkout-flow` in `src/cart/.purpose`. The flow references components from other directories — that is expected and correct.
|
|
62
|
+
|
|
63
|
+
You can also reference flows from component definitions:
|
|
64
|
+
|
|
65
|
+
```yaml
|
|
66
|
+
components:
|
|
67
|
+
#cart-service:
|
|
68
|
+
description: Shopping cart management
|
|
69
|
+
flows: ["$checkout-flow", "$cart-abandonment-flow"]
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
This bidirectional referencing lets `paradigm_ripple` calculate the full impact when you modify a component — it knows which flows pass through it.
|
|
73
|
+
|
|
74
|
+
## Flow Validation
|
|
75
|
+
|
|
76
|
+
Paradigm provides `paradigm_flow_check` to check that your flow definitions are consistent:
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
paradigm_flow_check({ flowId: "$checkout-flow", checkImplementation: true })
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
With `checkImplementation: true`, the validator goes beyond schema checks — it verifies that the referenced components exist in `.purpose` files, that the actions are implemented in the codebase, and that any signals listed are actually emitted. This catches drift between documentation and code.
|
|
83
|
+
|
|
84
|
+
You can also validate all flows at once by omitting the `flowId` parameter. This is useful as a pre-commit check or CI step.
|
|
85
|
+
|
|
86
|
+
## Circular Dependency Detection
|
|
87
|
+
|
|
88
|
+
When flows reference each other via `relatedFlows` or step-level `$flow` symbols, they form a dependency graph. Paradigm automatically detects circular dependencies in this graph using depth-first search.
|
|
89
|
+
|
|
90
|
+
A circular dependency looks like this:
|
|
91
|
+
|
|
92
|
+
```yaml
|
|
93
|
+
$checkout-flow:
|
|
94
|
+
relatedFlows: [$payment-flow]
|
|
95
|
+
$payment-flow:
|
|
96
|
+
relatedFlows: [$checkout-flow] # Creates a cycle!
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
When you run `paradigm_flow_check({})` (validate all flows), the output includes a `circularDependencies` section:
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
⚠ Circular Dependencies (1)
|
|
103
|
+
|
|
104
|
+
$checkout-flow → $payment-flow → $checkout-flow
|
|
105
|
+
|
|
106
|
+
Resolution: Break the cycle by extracting shared logic into a
|
|
107
|
+
separate flow, or remove one direction of the dependency.
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
To resolve circular dependencies:
|
|
111
|
+
1. **Extract shared logic** into a new flow that both original flows reference
|
|
112
|
+
2. **Remove one direction** if only one flow truly depends on the other
|
|
113
|
+
3. **Replace with signals** — use `!signal` communication instead of direct flow references
|
|
114
|
+
|
|
115
|
+
Circular dependencies are not just a documentation problem — they indicate architectural coupling that can lead to cascading failures and maintenance difficulty.
|
|
116
|
+
|
|
117
|
+
## Flows Are Documentation, Not Orchestration
|
|
118
|
+
|
|
119
|
+
A critical distinction: flows describe *what happens*, not *how to make it happen*. They are not workflow engines or saga orchestrators. Your code still calls services, handles errors, and manages state however it needs to. The flow definition is metadata that helps humans and AI agents understand the sequence — it does not replace your implementation.
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: N-para-201-gates-deep-dive
|
|
3
|
+
title: Gates in Depth
|
|
4
|
+
type: note
|
|
5
|
+
author: paradigm
|
|
6
|
+
created: '2026-04-22'
|
|
7
|
+
updated: '2026-04-22'
|
|
8
|
+
tags:
|
|
9
|
+
- course
|
|
10
|
+
- para-201
|
|
11
|
+
- gate-types-include
|
|
12
|
+
- check-expressions-are
|
|
13
|
+
- gates-chain-via
|
|
14
|
+
symbols: []
|
|
15
|
+
difficulty: beginner
|
|
16
|
+
estimatedMinutes: 4
|
|
17
|
+
prerequisites: []
|
|
18
|
+
category: paradigm-core
|
|
19
|
+
origin: imported
|
|
20
|
+
source: courses/para-201.json
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Gate Types
|
|
24
|
+
|
|
25
|
+
Gates are general-purpose condition checkers. While authorization is a common use case, gates can check any defined condition — feature flags, environment requirements, data prerequisites, system health, and more. Here are the common gate types:
|
|
26
|
+
|
|
27
|
+
**Auth gates** verify identity — is the user who they claim to be?
|
|
28
|
+
```yaml
|
|
29
|
+
^authenticated:
|
|
30
|
+
description: User must have a valid session
|
|
31
|
+
check: req.session.userId != null
|
|
32
|
+
type: auth
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Role gates** verify permission level — does the user hold the right role?
|
|
36
|
+
```yaml
|
|
37
|
+
^project-admin:
|
|
38
|
+
description: User must be an admin of the project
|
|
39
|
+
check: project.admins.includes(req.user.id)
|
|
40
|
+
type: role
|
|
41
|
+
requires: [^authenticated]
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**Ownership gates** verify resource ownership — does the user own this specific item?
|
|
45
|
+
```yaml
|
|
46
|
+
^comment-author:
|
|
47
|
+
description: User must be the author of this comment
|
|
48
|
+
check: comment.authorId === req.user.id
|
|
49
|
+
type: ownership
|
|
50
|
+
requires: [^authenticated]
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**State-precondition gates** verify system state — is the system in the right condition?
|
|
54
|
+
```yaml
|
|
55
|
+
^payment-method-exists:
|
|
56
|
+
description: User must have a payment method on file
|
|
57
|
+
check: user.paymentMethods.length > 0
|
|
58
|
+
type: state-precondition
|
|
59
|
+
requires: [^authenticated]
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Environment gates** verify deployment context — is the system running in the right environment?
|
|
63
|
+
```yaml
|
|
64
|
+
^production-only:
|
|
65
|
+
description: Action is restricted to production environment
|
|
66
|
+
check: process.env.NODE_ENV === 'production'
|
|
67
|
+
type: environment
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Capability gates** verify that a feature or capability is available:
|
|
71
|
+
```yaml
|
|
72
|
+
^feature-enabled:
|
|
73
|
+
description: The feature flag must be active for this user
|
|
74
|
+
check: features.isEnabled('new-checkout', req.user)
|
|
75
|
+
type: capability
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Data-readiness gates** verify that required data exists before proceeding:
|
|
79
|
+
```yaml
|
|
80
|
+
^profile-complete:
|
|
81
|
+
description: User must have completed their profile before accessing this feature
|
|
82
|
+
check: user.profile.isComplete === true
|
|
83
|
+
type: data-readiness
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
The `type` field is metadata for humans and tools — Paradigm does not enforce different behavior based on type. But categorizing gates helps AI agents suggest appropriate checks. Auth, role, and ownership are common in web applications, while state-precondition, environment, capability, and data-readiness gates are equally important across all disciplines.
|
|
87
|
+
|
|
88
|
+
## Check Expressions
|
|
89
|
+
|
|
90
|
+
The `check` field contains a **pseudo-code expression** that describes the gate's condition logic. It is not executable code — it is precise documentation:
|
|
91
|
+
|
|
92
|
+
```yaml
|
|
93
|
+
# Good: clear and implementable
|
|
94
|
+
check: project.members.some(m => m.userId === req.user.id && m.role === 'admin')
|
|
95
|
+
|
|
96
|
+
# Bad: too vague
|
|
97
|
+
check: user is admin
|
|
98
|
+
|
|
99
|
+
# Bad: too implementation-specific
|
|
100
|
+
check: await db.query('SELECT * FROM project_members WHERE...')
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The check should be specific enough that a developer can implement it from reading the expression, but abstract enough that it does not depend on a particular ORM or database.
|
|
104
|
+
|
|
105
|
+
## Gate Chains
|
|
106
|
+
|
|
107
|
+
Gates chain through the `requires` field. When a route specifies `[^authenticated, ^project-admin]`, the gates are checked in order:
|
|
108
|
+
|
|
109
|
+
1. `^authenticated` runs first. If it fails, the request is rejected (in HTTP, this is a 401 Unauthorized; other disciplines handle failure differently).
|
|
110
|
+
2. `^project-admin` runs next (which itself requires `^authenticated`, already passed). If it fails, the request is denied (in HTTP, a 403 Forbidden).
|
|
111
|
+
|
|
112
|
+
Chains prevent redundant checks. You never need to re-check authentication inside a role gate — the `requires` field guarantees it already passed.
|
|
113
|
+
|
|
114
|
+
Deep chains are possible but should be kept shallow for clarity:
|
|
115
|
+
```yaml
|
|
116
|
+
^super-admin:
|
|
117
|
+
requires: [^authenticated, ^org-admin] # ^org-admin itself requires ^authenticated
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## The Effects Field
|
|
121
|
+
|
|
122
|
+
Gates can trigger side effects when they pass, defined in the `effects` field:
|
|
123
|
+
|
|
124
|
+
```yaml
|
|
125
|
+
^first-purchase:
|
|
126
|
+
description: User is making their first purchase
|
|
127
|
+
check: user.purchaseCount === 0
|
|
128
|
+
type: state-precondition
|
|
129
|
+
requires: [^authenticated]
|
|
130
|
+
effects:
|
|
131
|
+
- id: first-purchase-badge
|
|
132
|
+
oneTime: true
|
|
133
|
+
- id: welcome-discount
|
|
134
|
+
oneTime: true
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
The `oneTime: true` flag ensures the effect triggers only once per user. Effects are useful for gamification, onboarding rewards, and analytics events. If a gate has no side effects, use `effects: []`.
|
|
138
|
+
|
|
139
|
+
## Implementing Gates
|
|
140
|
+
|
|
141
|
+
While `portal.yaml` defines *what* gates exist and *where* they apply, your application code must *implement* them. In web applications, the typical pattern is middleware (other disciplines use different enforcement mechanisms):
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
// Express middleware implementing ^authenticated
|
|
145
|
+
function authenticated(req, res, next) {
|
|
146
|
+
if (!req.session?.userId) {
|
|
147
|
+
return res.status(401).json({ error: 'Authentication required' });
|
|
148
|
+
}
|
|
149
|
+
next();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Express middleware implementing ^project-admin
|
|
153
|
+
function projectAdmin(req, res, next) {
|
|
154
|
+
const project = await Project.findById(req.params.id);
|
|
155
|
+
if (!project.admins.includes(req.user.id)) {
|
|
156
|
+
return res.status(403).json({ error: 'Admin access required' });
|
|
157
|
+
}
|
|
158
|
+
next();
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Route applying the gate chain from portal.yaml
|
|
162
|
+
router.put('/api/projects/:id', authenticated, projectAdmin, updateProject);
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
The key discipline: the `portal.yaml` definition and the implementation must match. If `portal.yaml` says an operation requires `^project-admin`, the code must actually enforce that check.
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: N-para-201-portal-protocol
|
|
3
|
+
title: The Portal Protocol
|
|
4
|
+
type: note
|
|
5
|
+
author: paradigm
|
|
6
|
+
created: '2026-04-22'
|
|
7
|
+
updated: '2026-04-22'
|
|
8
|
+
tags:
|
|
9
|
+
- course
|
|
10
|
+
- para-201
|
|
11
|
+
- specification-before-implementation
|
|
12
|
+
- four-steps-ask
|
|
13
|
+
- paradigmgatesforroute-suggests-gates
|
|
14
|
+
symbols: []
|
|
15
|
+
difficulty: beginner
|
|
16
|
+
estimatedMinutes: 4
|
|
17
|
+
prerequisites: []
|
|
18
|
+
category: paradigm-core
|
|
19
|
+
origin: imported
|
|
20
|
+
source: courses/para-201.json
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Specification Before Implementation
|
|
24
|
+
|
|
25
|
+
The Portal Protocol is Paradigm's prescribed workflow for adding guarded operations. Its core principle is **specification before implementation** — you define what conditions must be met before you write the handler code. This inverts the common (and dangerous) pattern of building functionality first and bolting on checks later.
|
|
26
|
+
|
|
27
|
+
The idea is universal: define what gates an operation needs before you implement the operation itself. In a web API, this means defining route gates before writing handlers. In a mobile app, it might mean specifying which screens require which conditions before building the UI. In a CLI tool, it means declaring what preconditions a command requires before writing the command logic.
|
|
28
|
+
|
|
29
|
+
## The Four Steps
|
|
30
|
+
|
|
31
|
+
### Step 1: Ask Paradigm
|
|
32
|
+
|
|
33
|
+
Before writing any handler, call `paradigm_gates_for_route` with the route and method:
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
paradigm_gates_for_route({ route: "/api/projects/:id/members", method: "POST" })
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
This tool analyzes your existing `portal.yaml` and suggests gates based on patterns:
|
|
40
|
+
- The route is under `/api/` → probably needs `^authenticated`
|
|
41
|
+
- It modifies a project resource → probably needs `^project-admin` or `^project-member`
|
|
42
|
+
- It is a POST (mutation) → higher gate requirements than a GET
|
|
43
|
+
|
|
44
|
+
The suggestions are not binding, but they catch common oversights. You might realize you need a gate you had not considered.
|
|
45
|
+
|
|
46
|
+
### Step 2: Add to portal.yaml
|
|
47
|
+
|
|
48
|
+
Add the route with its required gates:
|
|
49
|
+
|
|
50
|
+
```yaml
|
|
51
|
+
routes:
|
|
52
|
+
# Existing routes...
|
|
53
|
+
"POST /api/projects/:id/members": [^authenticated, ^project-admin]
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
If you need a new gate that does not exist yet, define it in the `gates` section:
|
|
57
|
+
|
|
58
|
+
```yaml
|
|
59
|
+
gates:
|
|
60
|
+
^project-admin:
|
|
61
|
+
description: User must be an admin of the project
|
|
62
|
+
check: project.admins.includes(req.user.id)
|
|
63
|
+
type: role
|
|
64
|
+
requires: [^authenticated]
|
|
65
|
+
effects: []
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Step 3: Implement the Gate Checks
|
|
69
|
+
|
|
70
|
+
Write the middleware or handler code that enforces each gate. The implementation must match the `check` expression in portal.yaml. How a failed gate manifests depends on your discipline:
|
|
71
|
+
|
|
72
|
+
- **Web APIs** return HTTP status codes (401 for failed identity checks, 403 for failed authorization)
|
|
73
|
+
- **Mobile apps** might disable UI elements or show an upgrade prompt
|
|
74
|
+
- **CLI tools** might exit with a specific error code and message
|
|
75
|
+
- **Desktop apps** might gray out menu items or show a dialog
|
|
76
|
+
|
|
77
|
+
Here is an example for a web API:
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
async function projectAdmin(req, res, next) {
|
|
81
|
+
const project = await Project.findById(req.params.id);
|
|
82
|
+
if (!project) {
|
|
83
|
+
return res.status(404).json({ error: 'Project not found' });
|
|
84
|
+
}
|
|
85
|
+
if (!project.admins.includes(req.user.id)) {
|
|
86
|
+
log.gate('^project-admin').warn('Access denied', {
|
|
87
|
+
userId: req.user.id,
|
|
88
|
+
projectId: req.params.id
|
|
89
|
+
});
|
|
90
|
+
return res.status(403).json({ error: 'Admin access required' });
|
|
91
|
+
}
|
|
92
|
+
req.project = project; // Attach for downstream use
|
|
93
|
+
next();
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Notice the Paradigm logger usage: `log.gate('^project-admin').warn(...)` for a denied gate.
|
|
98
|
+
|
|
99
|
+
### Step 4: Test Gate Failures
|
|
100
|
+
|
|
101
|
+
Verify that failing a gate produces the correct behavior. In a web API, this means testing rejection status codes:
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
it('rejects non-admin attempting to add member', async () => {
|
|
105
|
+
const res = await request(app)
|
|
106
|
+
.post('/api/projects/proj_123/members')
|
|
107
|
+
.set('Authorization', `Bearer ${memberToken}`) // member, not admin
|
|
108
|
+
.send({ email: 'newuser@example.com' });
|
|
109
|
+
|
|
110
|
+
expect(res.status).toBe(403);
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Test both the pass path (authorized user succeeds) and the fail path (unauthorized user is rejected). The concept of pass/fail is universal across all disciplines — only the specific failure response varies.
|
|
115
|
+
|
|
116
|
+
## Common Gate Patterns
|
|
117
|
+
|
|
118
|
+
Over time, projects develop recurring gate patterns:
|
|
119
|
+
|
|
120
|
+
| Pattern | Gate Name | Check |
|
|
121
|
+
|---------|-----------|-------|
|
|
122
|
+
| Any logged-in user | `^authenticated` | `req.user != null` |
|
|
123
|
+
| Resource membership | `^{resource}-member` | `resource.members.includes(req.user.id)` |
|
|
124
|
+
| Resource admin | `^{resource}-admin` | `resource.admins.includes(req.user.id)` |
|
|
125
|
+
| Resource creator | `^{resource}-creator` | `resource.createdBy === req.user.id` |
|
|
126
|
+
| Item author | `^{item}-author` | `item.authorId === req.user.id` |
|
|
127
|
+
| Feature flag | `^feature-{name}` | `features.isEnabled(name, req.user)` |
|
|
128
|
+
|
|
129
|
+
These patterns are reusable across projects. When you call `paradigm_gates_for_route`, the tool draws from these patterns to make suggestions.
|
|
130
|
+
|
|
131
|
+
## The Cost of Skipping the Protocol
|
|
132
|
+
|
|
133
|
+
The Portal Protocol makes conditions a first thought rather than an afterthought. By defining gates in portal.yaml before writing handlers, you create an auditable specification that is separate from (and checkable against) the implementation. Whether you are protecting API endpoints, gating CLI commands, or controlling feature access in a mobile app, the principle is the same: specify first, implement second.
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: N-para-201-signal-patterns
|
|
3
|
+
title: Signal Patterns
|
|
4
|
+
type: note
|
|
5
|
+
author: paradigm
|
|
6
|
+
created: '2026-04-22'
|
|
7
|
+
updated: '2026-04-22'
|
|
8
|
+
tags:
|
|
9
|
+
- course
|
|
10
|
+
- para-201
|
|
11
|
+
- business-signals-domain
|
|
12
|
+
- system-signals-infrastructure
|
|
13
|
+
- security-signals-auth
|
|
14
|
+
symbols: []
|
|
15
|
+
difficulty: beginner
|
|
16
|
+
estimatedMinutes: 3
|
|
17
|
+
prerequisites: []
|
|
18
|
+
category: paradigm-core
|
|
19
|
+
origin: imported
|
|
20
|
+
source: courses/para-201.json
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Events That Drive Side Effects
|
|
24
|
+
|
|
25
|
+
Signals (`!`) are Paradigm's mechanism for documenting **decoupled communication**. When a component emits a signal, it announces that something happened without caring who listens. This decoupling is fundamental to maintainable systems — the payment service should not know about the email service, the analytics tracker, or the loyalty points calculator. It just announces `!payment-completed` and moves on.
|
|
26
|
+
|
|
27
|
+
## Signal Categories
|
|
28
|
+
|
|
29
|
+
### Business Signals
|
|
30
|
+
|
|
31
|
+
Business signals represent **domain events** — things that matter to the business:
|
|
32
|
+
|
|
33
|
+
```yaml
|
|
34
|
+
!order-placed:
|
|
35
|
+
description: A new order has been successfully created
|
|
36
|
+
emitters: ["#order-service"]
|
|
37
|
+
category: business
|
|
38
|
+
data:
|
|
39
|
+
orderId: string
|
|
40
|
+
userId: string
|
|
41
|
+
total: number
|
|
42
|
+
|
|
43
|
+
!subscription-renewed:
|
|
44
|
+
description: A recurring subscription payment succeeded
|
|
45
|
+
emitters: ["#billing-service"]
|
|
46
|
+
category: business
|
|
47
|
+
|
|
48
|
+
!user-upgraded:
|
|
49
|
+
description: User upgraded from free to paid plan
|
|
50
|
+
emitters: ["#plan-service"]
|
|
51
|
+
category: business
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Business signals are the most important category. They define the key moments in your application's lifecycle. If you had to explain your system to a new team member, you would list these events.
|
|
55
|
+
|
|
56
|
+
### System Signals
|
|
57
|
+
|
|
58
|
+
System signals represent **infrastructure events** — things that matter to operations:
|
|
59
|
+
|
|
60
|
+
```yaml
|
|
61
|
+
!cache-invalidated:
|
|
62
|
+
description: A cache entry or cache region was cleared
|
|
63
|
+
emitters: ["#cache-manager"]
|
|
64
|
+
category: system
|
|
65
|
+
data:
|
|
66
|
+
region: string
|
|
67
|
+
reason: string
|
|
68
|
+
|
|
69
|
+
!database-failover:
|
|
70
|
+
description: Primary database failed, switched to replica
|
|
71
|
+
emitters: ["#database-pool"]
|
|
72
|
+
category: system
|
|
73
|
+
severity: warn
|
|
74
|
+
|
|
75
|
+
!rate-limit-exceeded:
|
|
76
|
+
description: A user or IP exceeded the API rate limit
|
|
77
|
+
emitters: ["#rate-limiter"]
|
|
78
|
+
category: system
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
System signals are consumed by monitoring, alerting, and health-check systems rather than by business logic.
|
|
82
|
+
|
|
83
|
+
### Security Signals
|
|
84
|
+
|
|
85
|
+
Security signals represent **authentication and authorization events**:
|
|
86
|
+
|
|
87
|
+
```yaml
|
|
88
|
+
!login-failed:
|
|
89
|
+
description: User provided invalid credentials
|
|
90
|
+
emitters: ["#auth-handler"]
|
|
91
|
+
category: security
|
|
92
|
+
data:
|
|
93
|
+
email: string
|
|
94
|
+
reason: string
|
|
95
|
+
ipAddress: string
|
|
96
|
+
|
|
97
|
+
!permission-denied:
|
|
98
|
+
description: Authenticated user tried to access a resource they lack permission for
|
|
99
|
+
emitters: ["#gate-middleware"]
|
|
100
|
+
category: security
|
|
101
|
+
|
|
102
|
+
!suspicious-activity:
|
|
103
|
+
description: Unusual access pattern detected (multiple failed logins, geographic anomaly)
|
|
104
|
+
emitters: ["#security-monitor"]
|
|
105
|
+
category: security
|
|
106
|
+
severity: error
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Security signals are critical for audit trails and intrusion detection. They should always include enough data to reconstruct what happened.
|
|
110
|
+
|
|
111
|
+
## Emitters and Listeners
|
|
112
|
+
|
|
113
|
+
Every signal has one or more **emitters** — the components that fire the event:
|
|
114
|
+
|
|
115
|
+
```yaml
|
|
116
|
+
!payment-completed:
|
|
117
|
+
emitters: ["#payment-service", "#manual-charge-handler"]
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Listeners are not defined on the signal itself — they are documented on the listening component:
|
|
121
|
+
|
|
122
|
+
```yaml
|
|
123
|
+
#email-service:
|
|
124
|
+
description: Sends transactional emails
|
|
125
|
+
listens: ["!payment-completed", "!user-created", "!password-reset-requested"]
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
This asymmetry is intentional. The emitter must know it is emitting (so it is declared on the signal). But the listener can be added or removed without changing the signal definition — true decoupling.
|
|
129
|
+
|
|
130
|
+
## Signals for Decoupled Side Effects
|
|
131
|
+
|
|
132
|
+
The power of signals is in the side effects they enable without direct coupling:
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
!order-placed is emitted by #order-service
|
|
136
|
+
→ #email-service listens → sends confirmation email
|
|
137
|
+
→ #analytics-tracker listens → records conversion event
|
|
138
|
+
→ #loyalty-service listens → awards loyalty points
|
|
139
|
+
→ #inventory-service listens → decrements stock
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
The order service knows nothing about these four listeners. You can add a fifth listener (say, `#slack-notifier`) without touching the order service at all. This is the architectural benefit of signal-based communication.
|
|
143
|
+
|
|
144
|
+
## The Data Field
|
|
145
|
+
|
|
146
|
+
Signals can declare a `data` schema describing the payload emitted with the event:
|
|
147
|
+
|
|
148
|
+
```yaml
|
|
149
|
+
!user-created:
|
|
150
|
+
description: A new user account was registered
|
|
151
|
+
emitters: ["#auth-handler"]
|
|
152
|
+
category: business
|
|
153
|
+
data:
|
|
154
|
+
userId: string
|
|
155
|
+
email: string
|
|
156
|
+
registrationSource: string
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
The data field is documentation, not runtime validation. It tells listeners what to expect in the event payload, reducing the need to read the emitter's source code.
|